From a1c9c9ff06ab15e697d5bac6ea6e5da2df840cf5 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 4 Feb 2020 14:21:59 -0500 Subject: [PATCH] c++: Fix ({ ... }) array mem-initializer. 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 | 8 ++++ gcc/cp/constexpr.c | 11 ++++- gcc/cp/init.c | 48 ++++++------------- .../g++.dg/cpp0x/constexpr-array23.C | 24 ++++++++++ gcc/testsuite/g++.dg/cpp0x/desig2.C | 4 +- gcc/testsuite/g++.dg/cpp0x/desig3.C | 4 +- gcc/testsuite/g++.dg/cpp0x/desig4.C | 4 +- gcc/testsuite/g++.dg/ext/array1.C | 2 +- gcc/testsuite/g++.dg/ext/flexary29.C | 2 +- gcc/testsuite/g++.dg/init/array28.C | 2 +- 10 files changed, 65 insertions(+), 44 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ab63ec7a0fe..53f414fc453 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2020-02-04 Jason Merrill + + 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 * coroutines.cc (find_promise_type): Delete unused forward diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 3962763fb21..c35ec5acc97 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 543d127abcd..625062b60ad 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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 index 00000000000..1323271a0a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C @@ -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 () { } diff --git a/gcc/testsuite/g++.dg/cpp0x/desig2.C b/gcc/testsuite/g++.dg/cpp0x/desig2.C index 5ac2d15d952..21724e04796 100644 --- a/gcc/testsuite/g++.dg/cpp0x/desig2.C +++ b/gcc/testsuite/g++.dg/cpp0x/desig2.C @@ -15,9 +15,9 @@ private: }; SomeClass::SomeClass() - : member({ + : member{ [INDEX1] = { .field = 0 }, [INDEX2] = { .field = 1 } - }) + } { } diff --git a/gcc/testsuite/g++.dg/cpp0x/desig3.C b/gcc/testsuite/g++.dg/cpp0x/desig3.C index 0a50b742d45..5c27833d5c1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/desig3.C +++ b/gcc/testsuite/g++.dg/cpp0x/desig3.C @@ -13,9 +13,9 @@ private: }; SomeClass::SomeClass() - : member({ + : member{ [INDEX1] = { .field = 0 }, [INDEX2] = { .field = 1 } - }) + } { } diff --git a/gcc/testsuite/g++.dg/cpp0x/desig4.C b/gcc/testsuite/g++.dg/cpp0x/desig4.C index ff88d82adc0..4180e0983ea 100644 --- a/gcc/testsuite/g++.dg/cpp0x/desig4.C +++ b/gcc/testsuite/g++.dg/cpp0x/desig4.C @@ -13,9 +13,9 @@ private: }; SomeClass::SomeClass() - : member({ + : member{ [INDEX1] = { .field = 0 }, // { dg-error "constant expression" } [INDEX2] = { .field = 1 } // { dg-error "constant expression" } - }) + } { } diff --git a/gcc/testsuite/g++.dg/ext/array1.C b/gcc/testsuite/g++.dg/ext/array1.C index 7e54dc91939..f4c3630be16 100644 --- a/gcc/testsuite/g++.dg/ext/array1.C +++ b/gcc/testsuite/g++.dg/ext/array1.C @@ -3,7 +3,7 @@ class A { public: - A() : argc(0), argv() { }; + A() : argc(0), argv() { }; // { dg-error "flexible array" } private: int argc; char* argv[]; diff --git a/gcc/testsuite/g++.dg/ext/flexary29.C b/gcc/testsuite/g++.dg/ext/flexary29.C index a696fd9804f..8fef06e6a97 100644 --- a/gcc/testsuite/g++.dg/ext/flexary29.C +++ b/gcc/testsuite/g++.dg/ext/flexary29.C @@ -4,7 +4,7 @@ struct A { - constexpr A() : i(), x() {} + constexpr A() : i(), x() {} // { dg-error "flexible" } int i; char x[]; }; diff --git a/gcc/testsuite/g++.dg/init/array28.C b/gcc/testsuite/g++.dg/init/array28.C index 8cf19ba4331..9869354279d 100644 --- a/gcc/testsuite/g++.dg/init/array28.C +++ b/gcc/testsuite/g++.dg/init/array28.C @@ -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]; }; -- 2.30.2