diff mbox series

[v2] c++: ICE with reference NSDMI [PR114854]

Message ID ZkNrr2vDreGpelgu@redhat.com
State New
Headers show
Series [v2] c++: ICE with reference NSDMI [PR114854] | expand

Commit Message

Marek Polacek May 14, 2024, 1:48 p.m. UTC
On Thu, May 09, 2024 at 03:47:54PM -0400, Jason Merrill wrote:
> On 5/9/24 12:04, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:
> > 
> >        /* A TARGET_EXPR that expresses direct-initialization should have been
> >           elided by cp_gimplify_init_expr.  */
> >        gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));
> > 
> > the TARGET_EXPR in question is created for the NSDMI in:
> > 
> >    class Vector { int m_size; };
> >    struct S {
> >      const Vector &vec{};
> >    };
> > 
> > where we first need to create a Vector{} temporary, and then bind the
> > vec reference to it.  The temporary is represented by a TARGET_EXPR
> > and it cannot be elided.  When we create an object of type S, we get
> > 
> >    D.2848 = {.vec=(const struct Vector &) &TARGET_EXPR <D.2840, {.m_size=0}>}
> > 
> > where the TARGET_EXPR is no longer direct-initializing anything.
> 
> Seems like the problem is in convert_like_internal:
> 
> >             bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
> >             if (abstract_virtuals_error (NULL_TREE, totype, complain))
> >               return error_mark_node;
> >             expr = build_value_init (totype, complain);
> >             expr = get_target_expr (expr, complain);
> >             if (expr != error_mark_node)
> >               {
> >                 TARGET_EXPR_LIST_INIT_P (expr) = true;
> > =>              TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
> >               }
> 
> My patch for 50930 assumed that if a CONSTRUCTOR represents syntactic
> direct-initialization, a resulting TARGET_EXPR is itself the direct
> initializer, but that isn't the case here; the temporary is
> copy-initialized.
> 
> We could calculate direct-initializanity from cand->flags, but perhaps we
> can just stop trying to set TARGET_EXPR_DIRECT_INIT_P here at all? We don't
> do that for other list-initialization in ck_user, I don't know why I thought
> it was needed for {} specifically.  It doesn't seem to be needed for the
> 50930 testcase.

...and it doesn't seem to be needed for any other test.  Then not setting
the flag in the first place is better than resetting it later, sure.

I thought about leaving a gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P)
in cp_build_addr_expr_1, but since we already have that assert when
gimplifying, I dropped it.

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

-- >8 --
Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:

      /* A TARGET_EXPR that expresses direct-initialization should have been
         elided by cp_gimplify_init_expr.  */
      gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));

the TARGET_EXPR in question is created for the NSDMI in:

  class Vector { int m_size; };
  struct S {
    const Vector &vec{};
  };

where we first need to create a Vector{} temporary, and then bind the
vec reference to it.  The temporary is represented by a TARGET_EXPR
and it cannot be elided.  When we create an object of type S, we get

  D.2848 = {.vec=(const struct Vector &) &TARGET_EXPR <D.2840, {.m_size=0}>}

where the TARGET_EXPR is no longer direct-initializing anything.

Fixed by not setting TARGET_EXPR_DIRECT_INIT_P in convert_like_internal/ck_user.

	PR c++/114854

gcc/cp/ChangeLog:

	* call.cc (convert_like_internal) <case ck_user>: Don't set
	TARGET_EXPR_DIRECT_INIT_P.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1y/nsdmi-aggr22.C: New test.
---
 gcc/cp/call.cc                            |  6 +-----
 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C | 12 ++++++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C


base-commit: 0a99ad5c52caa06c113b1889bbe6634812b89be5

Comments

Jason Merrill May 14, 2024, 10:09 p.m. UTC | #1
On 5/14/24 09:48, Marek Polacek wrote:
> On Thu, May 09, 2024 at 03:47:54PM -0400, Jason Merrill wrote:
>> On 5/9/24 12:04, Marek Polacek wrote:
>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>>>
>>> -- >8 --
>>> Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:
>>>
>>>         /* A TARGET_EXPR that expresses direct-initialization should have been
>>>            elided by cp_gimplify_init_expr.  */
>>>         gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));
>>>
>>> the TARGET_EXPR in question is created for the NSDMI in:
>>>
>>>     class Vector { int m_size; };
>>>     struct S {
>>>       const Vector &vec{};
>>>     };
>>>
>>> where we first need to create a Vector{} temporary, and then bind the
>>> vec reference to it.  The temporary is represented by a TARGET_EXPR
>>> and it cannot be elided.  When we create an object of type S, we get
>>>
>>>     D.2848 = {.vec=(const struct Vector &) &TARGET_EXPR <D.2840, {.m_size=0}>}
>>>
>>> where the TARGET_EXPR is no longer direct-initializing anything.
>>
>> Seems like the problem is in convert_like_internal:
>>
>>>              bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
>>>              if (abstract_virtuals_error (NULL_TREE, totype, complain))
>>>                return error_mark_node;
>>>              expr = build_value_init (totype, complain);
>>>              expr = get_target_expr (expr, complain);
>>>              if (expr != error_mark_node)
>>>                {
>>>                  TARGET_EXPR_LIST_INIT_P (expr) = true;
>>> =>              TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
>>>                }
>>
>> My patch for 50930 assumed that if a CONSTRUCTOR represents syntactic
>> direct-initialization, a resulting TARGET_EXPR is itself the direct
>> initializer, but that isn't the case here; the temporary is
>> copy-initialized.
>>
>> We could calculate direct-initializanity from cand->flags, but perhaps we
>> can just stop trying to set TARGET_EXPR_DIRECT_INIT_P here at all? We don't
>> do that for other list-initialization in ck_user, I don't know why I thought
>> it was needed for {} specifically.  It doesn't seem to be needed for the
>> 50930 testcase.
> 
> ...and it doesn't seem to be needed for any other test.  Then not setting
> the flag in the first place is better than resetting it later, sure.
> 
> I thought about leaving a gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P)
> in cp_build_addr_expr_1, but since we already have that assert when
> gimplifying, I dropped it.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/branches?

OK.

> -- >8 --
> Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:
> 
>        /* A TARGET_EXPR that expresses direct-initialization should have been
>           elided by cp_gimplify_init_expr.  */
>        gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));
> 
> the TARGET_EXPR in question is created for the NSDMI in:
> 
>    class Vector { int m_size; };
>    struct S {
>      const Vector &vec{};
>    };
> 
> where we first need to create a Vector{} temporary, and then bind the
> vec reference to it.  The temporary is represented by a TARGET_EXPR
> and it cannot be elided.  When we create an object of type S, we get
> 
>    D.2848 = {.vec=(const struct Vector &) &TARGET_EXPR <D.2840, {.m_size=0}>}
> 
> where the TARGET_EXPR is no longer direct-initializing anything.
> 
> Fixed by not setting TARGET_EXPR_DIRECT_INIT_P in convert_like_internal/ck_user.
> 
> 	PR c++/114854
> 
> gcc/cp/ChangeLog:
> 
> 	* call.cc (convert_like_internal) <case ck_user>: Don't set
> 	TARGET_EXPR_DIRECT_INIT_P.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp1y/nsdmi-aggr22.C: New test.
> ---
>   gcc/cp/call.cc                            |  6 +-----
>   gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C | 12 ++++++++++++
>   2 files changed, 13 insertions(+), 5 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index e058da7735f..ed68eb3c568 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -8597,16 +8597,12 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
>   	    && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype)
>   	    && !processing_template_decl)
>   	  {
> -	    bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
>   	    if (abstract_virtuals_error (NULL_TREE, totype, complain))
>   	      return error_mark_node;
>   	    expr = build_value_init (totype, complain);
>   	    expr = get_target_expr (expr, complain);
>   	    if (expr != error_mark_node)
> -	      {
> -		TARGET_EXPR_LIST_INIT_P (expr) = true;
> -		TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
> -	      }
> +	      TARGET_EXPR_LIST_INIT_P (expr) = true;
>   	    return expr;
>   	  }
>   
> diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
> new file mode 100644
> index 00000000000..a4f9ae19ca9
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
> @@ -0,0 +1,12 @@
> +// PR c++/114854
> +// { dg-do compile { target c++14 } }
> +
> +struct Vector {
> +  int m_size;
> +};
> +struct S {
> +  const Vector &vec{};
> +};
> +
> +void spawn(S);
> +void test() { spawn({}); }
> 
> base-commit: 0a99ad5c52caa06c113b1889bbe6634812b89be5
diff mbox series

Patch

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index e058da7735f..ed68eb3c568 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -8597,16 +8597,12 @@  convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
 	    && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype)
 	    && !processing_template_decl)
 	  {
-	    bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
 	    if (abstract_virtuals_error (NULL_TREE, totype, complain))
 	      return error_mark_node;
 	    expr = build_value_init (totype, complain);
 	    expr = get_target_expr (expr, complain);
 	    if (expr != error_mark_node)
-	      {
-		TARGET_EXPR_LIST_INIT_P (expr) = true;
-		TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
-	      }
+	      TARGET_EXPR_LIST_INIT_P (expr) = true;
 	    return expr;
 	  }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
new file mode 100644
index 00000000000..a4f9ae19ca9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
@@ -0,0 +1,12 @@ 
+// PR c++/114854
+// { dg-do compile { target c++14 } }
+
+struct Vector {
+  int m_size;
+};
+struct S {
+  const Vector &vec{};
+};
+
+void spawn(S);
+void test() { spawn({}); }