c++: re-enable NSDMI CONSTRUCTOR folding [PR118355]

Message ID 20250114162558.15438-1-polacek@redhat.com
State Committed
Commit e939005c496dfd4058fa57b6860bfadcabe4a111
Headers
Series c++: re-enable NSDMI CONSTRUCTOR folding [PR118355] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply

Commit Message

Marek Polacek Jan. 14, 2025, 4:25 p.m. UTC
  Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/branches?

-- >8 --
In c++/102990 we had a problem where massage_init_elt got {},
digest_nsdmi_init turned that {} into { .value = (int) 1.0e+0 },
and we crashed in the call to fold_non_dependent_init because
a FIX_TRUNC_EXPR/FLOAT_EXPR got into tsubst*.  So we avoided
calling fold_non_dependent_init for a CONSTRUCTOR.

But that broke the following test, where we no longer fold the
CONST_DECL in
  { .type = ZERO }
to
  { .type = 0 }
and then process_init_constructor_array does:

            if (next != error_mark_node
                && (initializer_constant_valid_p (next, TREE_TYPE (next))
                    != null_pointer_node))
              {
                /* Use VEC_INIT_EXPR for non-constant initialization of
                   trailing elements with no explicit initializers.  */
                picflags |= PICFLAG_VEC_INIT;

because { .type = ZERO } isn't initializer_constant_valid_p.  Then we
create a VEC_INIT_EXPR and say we can't convert the argument.

So we have to fold the elements of the CONSTRUCTOR.  We just can't
instantiate the elements in a template.

This also fixes c++/118047.

	PR c++/118047
	PR c++/118355

gcc/cp/ChangeLog:

	* typeck2.cc (massage_init_elt): Call fold_non_dependent_init
	unless for a CONSTRUCTOR in a template.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/nsdmi-list10.C: New test.
	* g++.dg/cpp0x/nsdmi-list9.C: New test.
---
 gcc/cp/typeck2.cc                         |  8 +++---
 gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C | 35 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C  | 34 ++++++++++++++++++++++
 3 files changed, 73 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C


base-commit: 22fe3c05d86b52c35850918bfb21e1f597e1b5c7
  

Comments

Jason Merrill Jan. 14, 2025, 5:45 p.m. UTC | #1
On 1/14/25 11:25 AM, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/branches?

OK for all.

> -- >8 --
> In c++/102990 we had a problem where massage_init_elt got {},
> digest_nsdmi_init turned that {} into { .value = (int) 1.0e+0 },
> and we crashed in the call to fold_non_dependent_init because
> a FIX_TRUNC_EXPR/FLOAT_EXPR got into tsubst*.  So we avoided
> calling fold_non_dependent_init for a CONSTRUCTOR.
> 
> But that broke the following test, where we no longer fold the
> CONST_DECL in
>    { .type = ZERO }
> to
>    { .type = 0 }
> and then process_init_constructor_array does:
> 
>              if (next != error_mark_node
>                  && (initializer_constant_valid_p (next, TREE_TYPE (next))
>                      != null_pointer_node))
>                {
>                  /* Use VEC_INIT_EXPR for non-constant initialization of
>                     trailing elements with no explicit initializers.  */
>                  picflags |= PICFLAG_VEC_INIT;
> 
> because { .type = ZERO } isn't initializer_constant_valid_p.  Then we
> create a VEC_INIT_EXPR and say we can't convert the argument.
> 
> So we have to fold the elements of the CONSTRUCTOR.  We just can't
> instantiate the elements in a template.
> 
> This also fixes c++/118047.
> 
> 	PR c++/118047
> 	PR c++/118355
> 
> gcc/cp/ChangeLog:
> 
> 	* typeck2.cc (massage_init_elt): Call fold_non_dependent_init
> 	unless for a CONSTRUCTOR in a template.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/nsdmi-list10.C: New test.
> 	* g++.dg/cpp0x/nsdmi-list9.C: New test.
> ---
>   gcc/cp/typeck2.cc                         |  8 +++---
>   gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C | 35 +++++++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C  | 34 ++++++++++++++++++++++
>   3 files changed, 73 insertions(+), 4 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C
> 
> diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
> index 5dae7fccf19..e2ab255a7d5 100644
> --- a/gcc/cp/typeck2.cc
> +++ b/gcc/cp/typeck2.cc
> @@ -1568,10 +1568,10 @@ massage_init_elt (tree type, tree init, int nested, int flags,
>       new_flags |= LOOKUP_AGGREGATE_PAREN_INIT;
>     init = digest_init_r (type, init, nested ? 2 : 1, new_flags, complain);
>     /* When we defer constant folding within a statement, we may want to
> -     defer this folding as well.  Don't call this on CONSTRUCTORs because
> -     their elements have already been folded, and we must avoid folding
> -     the result of get_nsdmi.  */
> -  if (TREE_CODE (init) != CONSTRUCTOR)
> +     defer this folding as well.  Don't call this on CONSTRUCTORs in
> +     a template because their elements have already been folded, and
> +     we must avoid folding the result of get_nsdmi.  */
> +  if (!(processing_template_decl && TREE_CODE (init) == CONSTRUCTOR))
>       {
>         tree t = fold_non_dependent_init (init, complain);
>         if (TREE_CONSTANT (t))
> diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C
> new file mode 100644
> index 00000000000..36b74749cbf
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C
> @@ -0,0 +1,35 @@
> +// PR c++/118047
> +// { dg-do compile { target c++11 } }
> +
> +typedef decltype(sizeof(char)) size_t;
> +
> +namespace std {
> +template <typename T>
> +struct initializer_list {
> +  const T *_M_array;
> +  size_t _M_len;
> +  constexpr size_t size() const { return _M_len; }
> +};
> +}
> +
> +enum E {
> +    One
> +};
> +
> +struct A {
> +    E e = One;
> +};
> +
> +struct B {
> +    A as[1] {};
> +};
> +
> +struct V
> +{
> +  constexpr V(const std::initializer_list<B> &a) : size(a.size()){}
> +  int size;
> +};
> +
> +constexpr V a{{}};
> +
> +static_assert(a.size == 1, "");
> diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C
> new file mode 100644
> index 00000000000..ae69ba0810d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C
> @@ -0,0 +1,34 @@
> +// PR c++/118355
> +// { dg-do compile { target c++11 } }
> +
> +enum MY_ENUM
> +{
> +  ZERO,
> +};
> +
> +struct FOO
> +{
> +  MY_ENUM type = ZERO;
> +};
> +
> +struct ARR
> +{
> +  FOO array[1] = {};
> +};
> +
> +template<typename>
> +struct ARR2
> +{
> +  FOO array[1] = {};
> +};
> +
> +void
> +g ()
> +{
> +
> +  ARR arr;
> +  arr = {};
> +
> +  ARR2<int> arr2;
> +  arr2 = {};
> +}
> 
> base-commit: 22fe3c05d86b52c35850918bfb21e1f597e1b5c7
  

Patch

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 5dae7fccf19..e2ab255a7d5 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1568,10 +1568,10 @@  massage_init_elt (tree type, tree init, int nested, int flags,
     new_flags |= LOOKUP_AGGREGATE_PAREN_INIT;
   init = digest_init_r (type, init, nested ? 2 : 1, new_flags, complain);
   /* When we defer constant folding within a statement, we may want to
-     defer this folding as well.  Don't call this on CONSTRUCTORs because
-     their elements have already been folded, and we must avoid folding
-     the result of get_nsdmi.  */
-  if (TREE_CODE (init) != CONSTRUCTOR)
+     defer this folding as well.  Don't call this on CONSTRUCTORs in
+     a template because their elements have already been folded, and
+     we must avoid folding the result of get_nsdmi.  */
+  if (!(processing_template_decl && TREE_CODE (init) == CONSTRUCTOR))
     {
       tree t = fold_non_dependent_init (init, complain);
       if (TREE_CONSTANT (t))
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C
new file mode 100644
index 00000000000..36b74749cbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list10.C
@@ -0,0 +1,35 @@ 
+// PR c++/118047
+// { dg-do compile { target c++11 } }
+
+typedef decltype(sizeof(char)) size_t;
+
+namespace std {
+template <typename T>
+struct initializer_list {
+  const T *_M_array;
+  size_t _M_len;
+  constexpr size_t size() const { return _M_len; }
+};
+}
+
+enum E {
+    One
+};
+
+struct A {
+    E e = One;
+};
+
+struct B {
+    A as[1] {};
+};
+
+struct V
+{
+  constexpr V(const std::initializer_list<B> &a) : size(a.size()){}
+  int size;
+};
+
+constexpr V a{{}};
+
+static_assert(a.size == 1, "");
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C
new file mode 100644
index 00000000000..ae69ba0810d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-list9.C
@@ -0,0 +1,34 @@ 
+// PR c++/118355
+// { dg-do compile { target c++11 } }
+
+enum MY_ENUM
+{
+  ZERO,
+};
+
+struct FOO
+{
+  MY_ENUM type = ZERO;
+};
+
+struct ARR
+{
+  FOO array[1] = {};
+};
+
+template<typename>
+struct ARR2
+{
+  FOO array[1] = {};
+};
+
+void
+g ()
+{
+
+  ARR arr;
+  arr = {};
+
+  ARR2<int> arr2;
+  arr2 = {};
+}