c++: Fix ({ ... }) array mem-initializer.
authorJason Merrill <jason@redhat.com>
Tue, 4 Feb 2020 19:21:59 +0000 (14:21 -0500)
committerJason Merrill <jason@redhat.com>
Tue, 4 Feb 2020 19:49:19 +0000 (14:49 -0500)
Here, we were going down the wrong path in perform_member_init because of
the incorrect parens around the mem-initializer for the array.  And then
cxx_eval_vec_init_1 didn't know what to do with a CONSTRUCTOR as the
initializer.  The latter issue was a straightforward fix, but I also wanted
to fix us silently accepting the parens, which led to factoring out handling
of TREE_LIST and flexarrays.  The latter led to adjusting the expected
behavior on flexary29.C: we should complain about the initializer, but not
complain about a missing initializer.

As I commented on PR 92812, in this process I noticed that we weren't
handling C++20 parenthesized aggregate initialization as a mem-initializer.
So my TREE_LIST handling includes a commented out section that should
probably be part of a future fix for that issue; with it uncommented we
continue to crash on the testcase in C++20 mode, but should instead complain
about the braced-init-list not being a valid initializer for an A.

PR c++/86917
* init.c (perform_member_init): Simplify.
* constexpr.c (cx_check_missing_mem_inits): Allow uninitialized
flexarray.
(cxx_eval_vec_init_1): Handle CONSTRUCTOR.

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/init.c
gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/desig2.C
gcc/testsuite/g++.dg/cpp0x/desig3.C
gcc/testsuite/g++.dg/cpp0x/desig4.C
gcc/testsuite/g++.dg/ext/array1.C
gcc/testsuite/g++.dg/ext/flexary29.C
gcc/testsuite/g++.dg/init/array28.C

index ab63ec7a0fed6ba2def0aa8aa037d7057efe8e7c..53f414fc45383fc689cfb719c4959dddd442d885 100644 (file)
@@ -1,3 +1,11 @@
+2020-02-04  Jason Merrill  <jason@redhat.com>
+
+       PR c++/86917
+       * init.c (perform_member_init): Simplify.
+       * constexpr.c (cx_check_missing_mem_inits): Allow uninitialized
+       flexarray.
+       (cxx_eval_vec_init_1): Handle CONSTRUCTOR.
+
 2020-02-04  Iain Sandoe  <iain@sandoe.co.uk>
 
        * coroutines.cc (find_promise_type): Delete unused forward
index 3962763fb21a6e47a5e1d0325f8965c52e656504..c35ec5acc9770b80a48122c26a2db3cacdd0cc02 100644 (file)
@@ -826,7 +826,12 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain)
                return true;
              continue;
            }
-         ftype = strip_array_types (TREE_TYPE (field));
+         ftype = TREE_TYPE (field);
+         if (!ftype || !TYPE_P (ftype) || !COMPLETE_TYPE_P (ftype))
+           /* A flexible array can't be intialized here, so don't complain
+              that it isn't.  */
+           continue;
+         ftype = strip_array_types (ftype);
          if (type_has_constexpr_default_constructor (ftype))
            {
              /* It's OK to skip a member with a trivial constexpr ctor.
@@ -3784,6 +3789,10 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
   unsigned HOST_WIDE_INT i;
   tsubst_flags_t complain = ctx->quiet ? tf_none : tf_warning_or_error;
 
+  if (init && TREE_CODE (init) == CONSTRUCTOR)
+    return cxx_eval_bare_aggregate (ctx, init, lval,
+                                   non_constant_p, overflow_p);
+
   /* For the default constructor, build up a call to the default
      constructor of the element type.  We only need to handle class types
      here, as for a constructor to be constexpr, all members must be
index 543d127abcd8079256385022d0c9d8aee1f6f9f0..625062b60adb5200024d7c8a274abb810ddf9b1b 100644 (file)
@@ -801,6 +801,17 @@ perform_member_init (tree member, tree init)
                    member);
     }
 
+  if (maybe_reject_flexarray_init (member, init))
+    return;
+
+  if (init && TREE_CODE (init) == TREE_LIST
+      && (DIRECT_LIST_INIT_P (TREE_VALUE (init))
+         /* FIXME C++20 parenthesized aggregate init (PR 92812).  */
+         || !(/* cxx_dialect >= cxx2a ? CP_AGGREGATE_TYPE_P (type) */
+              /* :  */CLASS_TYPE_P (type))))
+    init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
+                                           tf_warning_or_error);
+
   if (init == void_type_node)
     {
       /* mem() means value-initialization.  */
@@ -832,12 +843,7 @@ perform_member_init (tree member, tree init)
     }
   else if (init
           && (TYPE_REF_P (type)
-              /* Pre-digested NSDMI.  */
-              || (((TREE_CODE (init) == CONSTRUCTOR
-                    && TREE_TYPE (init) == type)
-                   /* { } mem-initializer.  */
-                   || (TREE_CODE (init) == TREE_LIST
-                       && DIRECT_LIST_INIT_P (TREE_VALUE (init))))
+              || (TREE_CODE (init) == CONSTRUCTOR
                   && (CP_AGGREGATE_TYPE_P (type)
                       || is_std_init_list (type)))))
     {
@@ -847,10 +853,7 @@ perform_member_init (tree member, tree init)
         persists until the constructor exits."  */
       unsigned i; tree t;
       releasing_vec cleanups;
-      if (TREE_CODE (init) == TREE_LIST)
-       init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
-                                               tf_warning_or_error);
-      if (TREE_TYPE (init) != type)
+      if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), type))
        {
          if (BRACE_ENCLOSED_INITIALIZER_P (init)
              && CP_AGGREGATE_TYPE_P (type))
@@ -876,23 +879,6 @@ perform_member_init (tree member, tree init)
     {
       if (TREE_CODE (type) == ARRAY_TYPE)
        {
-         if (init)
-           {
-             /* Check to make sure the member initializer is valid and
-                something like a CONSTRUCTOR in: T a[] = { 1, 2 } and
-                if it isn't, return early to avoid triggering another
-                error below.  */
-             if (maybe_reject_flexarray_init (member, init))
-               return;
-
-             if (TREE_CODE (init) != TREE_LIST || TREE_CHAIN (init))
-               init = error_mark_node;
-             else
-               init = TREE_VALUE (init);
-
-             if (BRACE_ENCLOSED_INITIALIZER_P (init))
-               init = digest_init (type, init, tf_warning_or_error);
-           }
          if (init == NULL_TREE
              || same_type_ignoring_top_level_qualifiers_p (type,
                                                            TREE_TYPE (init)))
@@ -962,16 +948,10 @@ perform_member_init (tree member, tree init)
                                                      /*using_new=*/false,
                                                      /*complain=*/true);
        }
-      else if (TREE_CODE (init) == TREE_LIST)
-       /* There was an explicit member initialization.  Do some work
-          in that case.  */
-       init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
-                                               tf_warning_or_error);
 
       maybe_warn_list_ctor (member, init);
 
-      /* Reject a member initializer for a flexible array member.  */
-      if (init && !maybe_reject_flexarray_init (member, init))
+      if (init)
        finish_expr_stmt (cp_build_modify_expr (input_location, decl,
                                                INIT_EXPR, init,
                                                tf_warning_or_error));
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C
new file mode 100644 (file)
index 0000000..1323271
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/86917
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  constexpr A () : c (0) {}
+  static const A z;
+  unsigned c;
+};
+
+struct B
+{                              // This should really be target { ! c++2a }
+  typedef A W[4];              // { dg-error "paren" "" { target *-*-* } .+1 }
+  constexpr B () : w ({ A::z, A::z, A::z, A::z }) {} // { dg-error "constant" }
+  W w;
+};
+
+struct C
+{
+  C ();
+  B w[1];
+};
+
+C::C () { }
index 5ac2d15d95216dccee242db413124d4f91e3f364..21724e047962d5d6c059b9c0764801115e0af0aa 100644 (file)
@@ -15,9 +15,9 @@ private:
 };
 
 SomeClass::SomeClass()
- : member({
+ : member{
    [INDEX1] = { .field = 0 },
    [INDEX2] = { .field = 1 }
- })
+ }
 {
 }
index 0a50b742d450eb1d949b11307088adf44b52d3c3..5c27833d5c19b1bb19dfcb397d076d9ba33db550 100644 (file)
@@ -13,9 +13,9 @@ private:
 };
 
 SomeClass::SomeClass()
- : member({
+ : member{
    [INDEX1] = { .field = 0 },
    [INDEX2] = { .field = 1 }
- })
+ }
 {
 }
index ff88d82adc079abe1261d483b89c40f93ce717fa..4180e0983eaafe7df1e751b3e6fa1b212c22d1a1 100644 (file)
@@ -13,9 +13,9 @@ private:
 };
 
 SomeClass::SomeClass()
- : member({
+ : member{
    [INDEX1] = { .field = 0 },  // { dg-error "constant expression" }
    [INDEX2] = { .field = 1 }   // { dg-error "constant expression" }
- })
+ }
 {
 }
index 7e54dc91939bfa33ebda813cc254c4300ee2b61d..f4c3630be1602e4ac7668f18894af7d980905d27 100644 (file)
@@ -3,7 +3,7 @@
 
 class A { 
 public: 
-  A() : argc(0), argv() { }; 
+  A() : argc(0), argv() { };   // { dg-error "flexible array" }
 private: 
   int argc; 
   char* argv[]; 
index a696fd9804f1dab7e7ff8e183a8c984db3e774e0..8fef06e6a978394a95c4d492f5c1bf68a510df0d 100644 (file)
@@ -4,7 +4,7 @@
 
 struct A
 {
-  constexpr A() : i(), x() {}
+  constexpr A() : i(), x() {}  // { dg-error "flexible" }
   int i;
   char x[];
 };
index 8cf19ba43310b6f02ff4e78af11146fd5c80541e..9869354279d1fb5c014ff755197c5b29b61350cb 100644 (file)
@@ -2,6 +2,6 @@
 
 struct Foo { explicit Foo(int) { } };
 struct Goo {
-  Goo() : x(Foo(4), Foo(5)) { } // { dg-error "array" }
+  Goo() : x(Foo(4), Foo(5)) { } // { dg-error "" }
   Foo x[2];
 };