public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
@ 2017-03-07 17:10 Marek Polacek
  2017-03-14  8:06 ` Marek Polacek
  2017-03-14 18:33 ` Jason Merrill
  0 siblings, 2 replies; 11+ messages in thread
From: Marek Polacek @ 2017-03-07 17:10 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill

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?

Bootstrapped/regtested on x86_64-linux, ok for trunk and 6?

2017-03-07  Marek Polacek  <polacek@redhat.com>

	PR c++/79937 - ICE in replace_placeholders_r
	* tree.c (replace_placeholders_r): Don't walk into CALL_EXPRs.

	* g++.dg/cpp1y/nsdmi-aggr7.C: New test.

diff --git gcc/cp/tree.c gcc/cp/tree.c
index d3c63b8..6a4f065 100644
--- gcc/cp/tree.c
+++ gcc/cp/tree.c
@@ -2751,6 +2751,11 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
 
   switch (TREE_CODE (*t))
     {
+    case CALL_EXPR:
+      /* Don't mess with placeholders in an unrelated object.  */
+      *walk_subtrees = false;
+      break;
+
     case PLACEHOLDER_EXPR:
       {
 	tree x = obj;
diff --git gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C
index e69de29..c2fd404 100644
--- gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C
+++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C
@@ -0,0 +1,21 @@
+// PR c++/79937
+// { dg-do compile { target c++14 } }
+
+struct C {};
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+};
+
+C
+bar (X)
+{
+  return {};
+}
+
+void
+foo ()
+{
+  C c = bar (X{1});
+}

	Marek

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-07 17:10 C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937) Marek Polacek
@ 2017-03-14  8:06 ` Marek Polacek
  2017-03-14 18:33 ` Jason Merrill
  1 sibling, 0 replies; 11+ messages in thread
From: Marek Polacek @ 2017-03-14  8:06 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill

Ping.

On Tue, Mar 07, 2017 at 06:10:48PM +0100, Marek Polacek 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?
> 
> Bootstrapped/regtested on x86_64-linux, ok for trunk and 6?
> 
> 2017-03-07  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c++/79937 - ICE in replace_placeholders_r
> 	* tree.c (replace_placeholders_r): Don't walk into CALL_EXPRs.
> 
> 	* g++.dg/cpp1y/nsdmi-aggr7.C: New test.
> 
> diff --git gcc/cp/tree.c gcc/cp/tree.c
> index d3c63b8..6a4f065 100644
> --- gcc/cp/tree.c
> +++ gcc/cp/tree.c
> @@ -2751,6 +2751,11 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
>  
>    switch (TREE_CODE (*t))
>      {
> +    case CALL_EXPR:
> +      /* Don't mess with placeholders in an unrelated object.  */
> +      *walk_subtrees = false;
> +      break;
> +
>      case PLACEHOLDER_EXPR:
>        {
>  	tree x = obj;
> diff --git gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C
> index e69de29..c2fd404 100644
> --- gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C
> +++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C
> @@ -0,0 +1,21 @@
> +// PR c++/79937
> +// { dg-do compile { target c++14 } }
> +
> +struct C {};
> +
> +struct X {
> +  unsigned i;
> +  unsigned n = i;
> +};
> +
> +C
> +bar (X)
> +{
> +  return {};
> +}
> +
> +void
> +foo ()
> +{
> +  C c = bar (X{1});
> +}
> 
> 	Marek

	Marek

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-07 17:10 C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937) Marek Polacek
  2017-03-14  8:06 ` Marek Polacek
@ 2017-03-14 18:33 ` Jason Merrill
  2017-03-14 18:34   ` Jason Merrill
  1 sibling, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2017-03-14 18:33 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-14 18:33 ` Jason Merrill
@ 2017-03-14 18:34   ` Jason Merrill
  2017-03-23 20:37     ` Marek Polacek
  0 siblings, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2017-03-14 18:34 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Tue, Mar 14, 2017 at 2:33 PM, Jason Merrill <jason@redhat.com> wrote:
> On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-14 18:34   ` Jason Merrill
@ 2017-03-23 20:37     ` Marek Polacek
  2017-03-23 21:24       ` Jason Merrill
  0 siblings, 1 reply; 11+ messages in thread
From: Marek Polacek @ 2017-03-23 20:37 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Tue, Mar 14, 2017 at 02:34:30PM -0400, Jason Merrill wrote:
> On Tue, Mar 14, 2017 at 2:33 PM, Jason Merrill <jason@redhat.com> wrote:
> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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?

Thanks,

	Marek

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-23 20:37     ` Marek Polacek
@ 2017-03-23 21:24       ` Jason Merrill
  2017-03-24 17:13         ` Marek Polacek
  0 siblings, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2017-03-23 21:24 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Thu, Mar 23, 2017 at 4:34 PM, Marek Polacek <polacek@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 <jason@redhat.com> wrote:
>> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-23 21:24       ` Jason Merrill
@ 2017-03-24 17:13         ` Marek Polacek
  2017-04-03 11:55           ` Marek Polacek
  2017-04-07 19:27           ` Jason Merrill
  0 siblings, 2 replies; 11+ messages in thread
From: Marek Polacek @ 2017-03-24 17:13 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Thu, Mar 23, 2017 at 05:09:58PM -0400, Jason Merrill wrote:
> On Thu, Mar 23, 2017 at 4:34 PM, Marek Polacek <polacek@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 <jason@redhat.com> wrote:
> >> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-24 17:13         ` Marek Polacek
@ 2017-04-03 11:55           ` Marek Polacek
  2017-04-07 19:27           ` Jason Merrill
  1 sibling, 0 replies; 11+ messages in thread
From: Marek Polacek @ 2017-04-03 11:55 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

Ping.  Any ideas how to move this forward?

On Fri, Mar 24, 2017 at 05:22:00PM +0100, Marek Polacek wrote:
> On Thu, Mar 23, 2017 at 05:09:58PM -0400, Jason Merrill wrote:
> > On Thu, Mar 23, 2017 at 4:34 PM, Marek Polacek <polacek@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 <jason@redhat.com> wrote:
> > >> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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

	Marek

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-03-24 17:13         ` Marek Polacek
  2017-04-03 11:55           ` Marek Polacek
@ 2017-04-07 19:27           ` Jason Merrill
  2017-04-25 16:33             ` Marek Polacek
  1 sibling, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2017-04-07 19:27 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Fri, Mar 24, 2017 at 12:22 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Thu, Mar 23, 2017 at 05:09:58PM -0400, Jason Merrill wrote:
>> On Thu, Mar 23, 2017 at 4:34 PM, Marek Polacek <polacek@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 <jason@redhat.com> wrote:
>> >> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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...

I was thinking that we want to replace the type of the first entry in
the stack (B, C, B respectively), and leave others alone.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-04-07 19:27           ` Jason Merrill
@ 2017-04-25 16:33             ` Marek Polacek
  2017-05-03 18:47               ` Jason Merrill
  0 siblings, 1 reply; 11+ messages in thread
From: Marek Polacek @ 2017-04-25 16:33 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Fri, Apr 07, 2017 at 03:27:36PM -0400, Jason Merrill wrote:
> On Fri, Mar 24, 2017 at 12:22 PM, Marek Polacek <polacek@redhat.com> wrote:
> > On Thu, Mar 23, 2017 at 05:09:58PM -0400, Jason Merrill wrote:
> >> On Thu, Mar 23, 2017 at 4:34 PM, Marek Polacek <polacek@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 <jason@redhat.com> wrote:
> >> >> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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...
> 
> I was thinking that we want to replace the type of the first entry in
> the stack (B, C, B respectively), and leave others alone.

Even that didn't work for me, because we may end up with a case of

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

Oh well.  So I abandoned the idea of stacks and tried this straightforward
approach, which seems to work fine:

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2017-04-25  Marek Polacek  <polacek@redhat.com>

	PR c++/79937
	* tree.c (replace_placeholders_r): Don't substitute an object of
	unrelated type.

	* g++.dg/cpp1y/nsdmi-aggr10.C: New test.
	* g++.dg/cpp1y/nsdmi-aggr9.C: New test.

diff --git gcc/cp/tree.c gcc/cp/tree.c
index 15b3ad9..5391df8 100644
--- gcc/cp/tree.c
+++ gcc/cp/tree.c
@@ -2789,11 +2789,20 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
     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 = false;
+	while (!(same_type_ignoring_top_level_qualifiers_p
+		 (TREE_TYPE (*t), TREE_TYPE (x))))
+	  if (TREE_CODE (x) != COMPONENT_REF)
+	    {
+	      /* An object of unrelated type; don't substitute.  */
+	      skip = true;
+	      break;
+	    }
+	  else
+	    x = TREE_OPERAND (x, 0);
+
+	if (!skip)
+	  *t = x;
 	*walk_subtrees = false;
 	d->seen = true;
       }
diff --git gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr10.C gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr10.C
index e69de29..1e051d8 100644
--- gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr10.C
+++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr10.C
@@ -0,0 +1,16 @@
+// PR c++/79937
+// { dg-do compile { target c++14 } }
+
+extern int frob (int);
+
+struct A
+{
+  int i;
+  int j = frob (this->i);
+};
+
+void
+foo ()
+{
+  A a = { 1 };
+}
diff --git gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr9.C gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr9.C
index e69de29..c2fd404 100644
--- gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr9.C
+++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr9.C
@@ -0,0 +1,21 @@
+// PR c++/79937
+// { dg-do compile { target c++14 } }
+
+struct C {};
+
+struct X {
+  unsigned i;
+  unsigned n = i;
+};
+
+C
+bar (X)
+{
+  return {};
+}
+
+void
+foo ()
+{
+  C c = bar (X{1});
+}


	Marek

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937)
  2017-04-25 16:33             ` Marek Polacek
@ 2017-05-03 18:47               ` Jason Merrill
  0 siblings, 0 replies; 11+ messages in thread
From: Jason Merrill @ 2017-05-03 18:47 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Tue, Apr 25, 2017 at 12:17 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Fri, Apr 07, 2017 at 03:27:36PM -0400, Jason Merrill wrote:
>> On Fri, Mar 24, 2017 at 12:22 PM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Thu, Mar 23, 2017 at 05:09:58PM -0400, Jason Merrill wrote:
>> >> On Thu, Mar 23, 2017 at 4:34 PM, Marek Polacek <polacek@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 <jason@redhat.com> wrote:
>> >> >> > On Tue, Mar 7, 2017 at 12:10 PM, Marek Polacek <polacek@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...
>>
>> I was thinking that we want to replace the type of the first entry in
>> the stack (B, C, B respectively), and leave others alone.
>
> Even that didn't work for me, because we may end up with a case of
>
>   C c = bar (T_E <D2, &<P_E struct X>>)

Why is that a problem?

Your patch doesn't fix this variant:

struct X {
  unsigned i;
  unsigned n = i;
};

unsigned int
bar (X x)
{
  return x.n;
}

int main()
{
  X x = { 2, bar (X{1}) };
  if (x.n != 1)
    __builtin_abort ();
}

Here we have two X objects, and we need to recognize them as distinct.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2017-05-03 18:46 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-07 17:10 C++ PATCH to fix ICE in replace_placeholders_r (PR c++/79937) Marek Polacek
2017-03-14  8:06 ` Marek Polacek
2017-03-14 18:33 ` Jason Merrill
2017-03-14 18:34   ` Jason Merrill
2017-03-23 20:37     ` Marek Polacek
2017-03-23 21:24       ` Jason Merrill
2017-03-24 17:13         ` Marek Polacek
2017-04-03 11:55           ` Marek Polacek
2017-04-07 19:27           ` Jason Merrill
2017-04-25 16:33             ` Marek Polacek
2017-05-03 18:47               ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).