From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) by sourceware.org (Postfix) with ESMTP id DBCE538708B9 for ; Wed, 2 Sep 2020 20:37:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org DBCE538708B9 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-430-gfnkm9eiMpGEK5rBPOXUSg-1; Wed, 02 Sep 2020 16:37:52 -0400 X-MC-Unique: gfnkm9eiMpGEK5rBPOXUSg-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id AF91518A2257 for ; Wed, 2 Sep 2020 20:37:51 +0000 (UTC) Received: from redhat.com (ovpn-116-133.rdu2.redhat.com [10.10.116.133]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1EFEC7E313; Wed, 2 Sep 2020 20:37:51 +0000 (UTC) Date: Wed, 2 Sep 2020 16:37:49 -0400 From: Marek Polacek To: Jason Merrill Cc: GCC Patches Subject: Re: [PATCH v2] c++: Fix P0960 in member init list and array [PR92812] Message-ID: <20200902203749.GK5926@redhat.com> References: <20200901222354.234729-1-polacek@redhat.com> <76109e86-fce4-00d4-8fba-f8f57df36da5@redhat.com> MIME-Version: 1.0 In-Reply-To: <76109e86-fce4-00d4-8fba-f8f57df36da5@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Mimecast-Spam-Score: 0.002 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-14.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Sep 2020 20:37:57 -0000 On Wed, Sep 02, 2020 at 12:00:29PM -0400, Jason Merrill via Gcc-patches wrote: > On 9/1/20 6:23 PM, Marek Polacek wrote: > > This patch nails down the remaining P0960 case in PR92812: > > > > struct A { > > int ar[2]; > > A(): ar(1, 2) {} // doesn't work without this patch > > }; > > > > Note that when the target object is not of array type, this already > > works: > > > > struct S { int x, y; }; > > struct A { > > S s; > > A(): s(1, 2) { } // OK in C++20 > > }; > > > > because build_new_method_call_1 takes care of the P0960 magic. > > > > It proved to be quite hairy. When the ()-list has more than one > > element, we can always create a CONSTRUCTOR, because the code was > > previously invalid. But when the ()-list has just one element, it > > gets all kinds of difficult. As usual, we have to handle a("foo") > > so as not to wrap the STRING_CST in a CONSTRUCTOR. Always turning > > x(e) into x{e} would run into trouble as in c++/93790. Another > > issue was what to do about x({e}): previously, this would trigger > > "list-initializer for non-class type must not be parenthesized". > > I figured I'd make this work in C++20, so that given > > > > struct S { int x, y; }; > > > > you can do > > > > S a[2]; > > [...] > > A(): a({1, 2}) // initialize a[0] with {1, 2} and a[1] with {} > > > > It also turned out that, as an extension, we support compound literals: > > > > F (): m((S[1]) { 1, 2 }) > > > > so this has to keep working as before. > > > > Moreover, make sure not to trigger in compiler-generated code, like > > =default, where array assignment is allowed. > > > > paren-init35.C also tests this with vector types. > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > > > gcc/cp/ChangeLog: > > > > PR c++/92812 > > * init.c (do_paren_init_for_array_p): New. > > (perform_member_init): Use it. If true, build up a CONSTRUCTOR > > from the list of arguments. > > > > gcc/testsuite/ChangeLog: > > > > PR c++/92812 > > * g++.dg/cpp0x/constexpr-array23.C: Adjust dg-error. > > * g++.dg/cpp0x/initlist69.C: Likewise. > > * g++.dg/diagnostic/mem-init1.C: Likewise. > > * g++.dg/init/array28.C: Likewise. > > * g++.dg/cpp2a/paren-init33.C: New test. > > * g++.dg/cpp2a/paren-init34.C: New test. > > * g++.dg/cpp2a/paren-init35.C: New test. > > * g++.old-deja/g++.brendan/crash60.C: Adjust dg-error. > > * g++.old-deja/g++.law/init10.C: Likewise. > > * g++.old-deja/g++.other/array3.C: Likewise. > > --- > > gcc/cp/init.c | 64 ++++++++- > > .../g++.dg/cpp0x/constexpr-array23.C | 6 +- > > gcc/testsuite/g++.dg/cpp0x/initlist69.C | 4 +- > > gcc/testsuite/g++.dg/cpp2a/paren-init33.C | 128 ++++++++++++++++++ > > gcc/testsuite/g++.dg/cpp2a/paren-init34.C | 25 ++++ > > gcc/testsuite/g++.dg/cpp2a/paren-init35.C | 21 +++ > > gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 4 +- > > gcc/testsuite/g++.dg/init/array28.C | 2 +- > > .../g++.old-deja/g++.brendan/crash60.C | 2 +- > > gcc/testsuite/g++.old-deja/g++.law/init10.C | 2 +- > > gcc/testsuite/g++.old-deja/g++.other/array3.C | 3 +- > > 11 files changed, 243 insertions(+), 18 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init33.C > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init34.C > > create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init35.C > > > > diff --git a/gcc/cp/init.c b/gcc/cp/init.c > > index d4540db3605..2edc9651ad6 100644 > > --- a/gcc/cp/init.c > > +++ b/gcc/cp/init.c > > @@ -756,6 +756,41 @@ maybe_warn_list_ctor (tree member, tree init) > > "of the underlying array", member, begin); > > } > > +/* Return true if we should attempt to perform the P0960 magic when > > + initializing an array TYPE from a parenthesized list of values LIST. */ > > + > > +static bool > > +do_paren_init_for_array_p (tree list, tree type) > > +{ > > + if (cxx_dialect < cxx20) > > + /* P0960 is a C++20 feature. */ > > + return false; > > + > > + const int len = list_length (list); > > + if (len == 0) > > + /* Value-initialization. */ > > + return false; > > + else if (len > 1) > > + /* If the list had more than one element, the code is ill-formed > > + pre-C++20, so we should attempt to ()-init. */ > > + return true; > > + > > + /* Lists with one element are trickier. */ > > + tree elt = TREE_VALUE (list); > > + > > + /* For a("foo"), don't wrap the STRING_CST in { }. */ > > + if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) > > + && TREE_CODE (tree_strip_any_location_wrapper (elt)) == STRING_CST) > > + return false; > > Hmm, yet another place we need to implement the special treatment of > strings? Can't we factor this better? Could there be a general e.g. > maybe_aggregate_paren_init function to turn a list into a CONSTRUCTOR that's > used in various places? I've added do_aggregate_paren_init to factor some common code. It's not perfect because the enclosing conditions couldn't really be factored out, but at least we don't have to repeat the special treatment of strings. Let's see if I can find a similar opportunity when dealing with the new int[4](1, 2, 3, 4); issue in the other thread... > > + /* Don't trigger in compiler-generated code for = default. */ > > + if (current_function_decl && DECL_DEFAULTED_FN (current_function_decl)) > > + return false; > > + > > + /* Handle non-standard extensions like compound literals. */ > > + return !same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (elt)); > > Isn't the defaulted function case caught by the same-type check? Yes it is, dropped. Thanks! Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- This patch nails down the remaining P0960 case in PR92812: struct A { int ar[2]; A(): ar(1, 2) {} // doesn't work without this patch }; Note that when the target object is not of array type, this already works: struct S { int x, y; }; struct A { S s; A(): s(1, 2) { } // OK in C++20 }; because build_new_method_call_1 takes care of the P0960 magic. It proved to be quite hairy. When the ()-list has more than one element, we can always create a CONSTRUCTOR, because the code was previously invalid. But when the ()-list has just one element, it gets all kinds of difficult. As usual, we have to handle a("foo") so as not to wrap the STRING_CST in a CONSTRUCTOR. Always turning x(e) into x{e} would run into trouble as in c++/93790. Another issue was what to do about x({e}): previously, this would trigger "list-initializer for non-class type must not be parenthesized". I figured I'd make this work in C++20, so that given struct S { int x, y; }; you can do S a[2]; [...] A(): a({1, 2}) // initialize a[0] with {1, 2} and a[1] with {} It also turned out that, as an extension, we support compound literals: F (): m((S[1]) { 1, 2 }) so this has to keep working as before. Moreover, make sure not to trigger in compiler-generated code, like =default, where array assignment is allowed. I've factored out a function that turns a TREE_LIST into a CONSTRUCTOR to simplify handling of P0960. paren-init35.C also tests this with vector types. gcc/cp/ChangeLog: PR c++/92812 * cp-tree.h (do_aggregate_paren_init): Declare. * decl.c (do_aggregate_paren_init): New. (grok_reference_init): Use it. (check_initializer): Likewise. * init.c (perform_member_init): Handle initializing an array from a ()-list. Use do_aggregate_paren_init. gcc/testsuite/ChangeLog: PR c++/92812 * g++.dg/cpp0x/constexpr-array23.C: Adjust dg-error. * g++.dg/cpp0x/initlist69.C: Likewise. * g++.dg/diagnostic/mem-init1.C: Likewise. * g++.dg/init/array28.C: Likewise. * g++.dg/cpp2a/paren-init33.C: New test. * g++.dg/cpp2a/paren-init34.C: New test. * g++.dg/cpp2a/paren-init35.C: New test. * g++.old-deja/g++.brendan/crash60.C: Adjust dg-error. * g++.old-deja/g++.law/init10.C: Likewise. * g++.old-deja/g++.other/array3.C: Likewise. --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 62 +++++---- gcc/cp/init.c | 35 ++++- .../g++.dg/cpp0x/constexpr-array23.C | 6 +- gcc/testsuite/g++.dg/cpp0x/initlist69.C | 4 +- gcc/testsuite/g++.dg/cpp2a/paren-init33.C | 128 ++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/paren-init34.C | 25 ++++ gcc/testsuite/g++.dg/cpp2a/paren-init35.C | 21 +++ gcc/testsuite/g++.dg/diagnostic/mem-init1.C | 4 +- gcc/testsuite/g++.dg/init/array28.C | 2 +- .../g++.old-deja/g++.brendan/crash60.C | 2 +- gcc/testsuite/g++.old-deja/g++.law/init10.C | 2 +- gcc/testsuite/g++.old-deja/g++.other/array3.C | 3 +- 13 files changed, 248 insertions(+), 47 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init33.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init34.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init35.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2b7c9b9913a..708de83eb46 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6582,6 +6582,7 @@ extern bool check_array_designated_initializer (constructor_elt *, extern bool check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); extern tree build_explicit_specifier (tree, tsubst_flags_t); extern void do_push_parm_decls (tree, tree, tree *); +extern tree do_aggregate_paren_init (tree, tree); /* in decl2.c */ extern void record_mangling (tree, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4c84f2d0a9b..250f3772a05 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5557,6 +5557,37 @@ start_decl_1 (tree decl, bool initialized) maybe_push_cleanup_level (type); } +/* Given a parenthesized list of values INIT, create a CONSTRUCTOR to handle + C++20 P0960. TYPE is the type of the object we're initializing. */ + +tree +do_aggregate_paren_init (tree init, tree type) +{ + tree val = TREE_VALUE (init); + + /* [dcl.init.string] "An array of ordinary character type [...] + can be initialized by an ordinary string literal [...] by an + appropriately-typed string literal enclosed in braces" only + talks about braces, but GCC has always accepted + + char a[]("foobar"); + + so we continue to do so. */ + if (TREE_CHAIN (init) == NULL_TREE + && TREE_CODE (type) == ARRAY_TYPE + && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) + && TREE_CODE (tree_strip_any_location_wrapper (val)) + == STRING_CST) + /* If the list has a single element and it's a string literal, + then it's the initializer for the array as a whole. */ + return val; + + init = build_constructor_from_list (init_list_type_node, init); + CONSTRUCTOR_IS_DIRECT_INIT (init) = true; + CONSTRUCTOR_IS_PAREN_INIT (init) = true; + return init; +} + /* Handle initialization of references. DECL, TYPE, and INIT have the same meaning as in cp_finish_decl. *CLEANUP must be NULL on entry, but will be set to a new CLEANUP_STMT if a temporary is created @@ -5604,11 +5635,7 @@ grok_reference_init (tree decl, tree type, tree init, int flags) /* If the list had more than one element, the code is ill-formed pre-C++20, so we can build a constructor right away. */ else - { - init = build_constructor_from_list (init_list_type_node, init); - CONSTRUCTOR_IS_DIRECT_INIT (init) = true; - CONSTRUCTOR_IS_PAREN_INIT (init) = true; - } + init = do_aggregate_paren_init (init, ttype); } else init = build_x_compound_expr_from_list (init, ELK_INIT, @@ -6794,30 +6821,7 @@ check_initializer (tree decl, tree init, int flags, vec **cleanups) && TREE_CODE (type) == ARRAY_TYPE && !DECL_DECOMPOSITION_P (decl) && (cxx_dialect >= cxx20)) - { - /* [dcl.init.string] "An array of ordinary character type [...] - can be initialized by an ordinary string literal [...] by an - appropriately-typed string literal enclosed in braces" only - talks about braces, but GCC has always accepted - - char a[]("foobar"); - - so we continue to do so. */ - tree val = TREE_VALUE (init); - if (TREE_CHAIN (init) == NULL_TREE - && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) - && TREE_CODE (tree_strip_any_location_wrapper (val)) - == STRING_CST) - /* If the list has a single element and it's a string literal, - then it's the initializer for the array as a whole. */ - init = val; - else - { - init = build_constructor_from_list (init_list_type_node, init); - CONSTRUCTOR_IS_DIRECT_INIT (init) = true; - CONSTRUCTOR_IS_PAREN_INIT (init) = true; - } - } + init = do_aggregate_paren_init (init, type); else if (TREE_CODE (init) == TREE_LIST && TREE_TYPE (init) != unknown_type_node && !MAYBE_CLASS_TYPE_P (type)) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index d4540db3605..65fa2259f9d 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -809,13 +809,34 @@ perform_member_init (tree member, tree 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 >= cxx20 ? 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 && TREE_CODE (init) == TREE_LIST) + { + /* A(): a{e} */ + if (DIRECT_LIST_INIT_P (TREE_VALUE (init))) + init = build_x_compound_expr_from_list (init, ELK_MEM_INIT, + tf_warning_or_error); + /* We are trying to initialize an array from a ()-list. If we + should attempt to do so, conjure up a CONSTRUCTOR. */ + else if (TREE_CODE (type) == ARRAY_TYPE + /* P0960 is a C++20 feature. */ + && (cxx_dialect >= cxx20) + /* Previously ill-formed code. */ + && (list_length (init) > 1 + /* A single-element list: handle non-standard extensions + like compound literals. This also prevents triggering + aggregate ()-initialization in compiler-generated code + for =default. */ + || (list_length (init) == 1 + && !same_type_ignoring_top_level_qualifiers_p + (type, TREE_TYPE (TREE_VALUE (init)))))) + init = do_aggregate_paren_init (init, type); + else if (!CLASS_TYPE_P (type)) + init = build_x_compound_expr_from_list (init, ELK_MEM_INIT, + tf_warning_or_error); + /* If we're initializing a class from a ()-list, leave the TREE_LIST + alone: we might call an appropriate constructor, or (in C++20) + do aggregate-initialization. */ + } if (init == void_type_node) { diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C index 1323271a0a5..1829fa7a653 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array23.C @@ -9,9 +9,9 @@ struct A }; 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" } +{ + typedef A W[4]; // { dg-error "paren" "" { target { ! c++20 } } .+1 } + constexpr B () : w ({ A::z, A::z, A::z, A::z }) {} // { dg-error "constant|could not convert" } W w; }; diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist69.C b/gcc/testsuite/g++.dg/cpp0x/initlist69.C index 7995f595a47..893a4e92cd3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/initlist69.C +++ b/gcc/testsuite/g++.dg/cpp0x/initlist69.C @@ -6,14 +6,14 @@ struct ca { T elem[1]; ca(const T (&s)[1]): elem{{s}} { } // { dg-error "invalid" } - ca(const T (&s)[1],int): elem({{s}}) { } // { dg-error "paren|invalid" } + ca(const T (&s)[1],int): elem({{s}}) { } // { dg-error "paren|invalid|too many" } ca(const T (&s)[1],char): elem(s) { } // { dg-error "array" } ca(const T (&s)[1],double): elem{s} { } // { dg-error "invalid" } ca(const T &v): elem{{v}} { } // OK ca(const T &v,int): elem{{{v}}} { } // { dg-error "braces" } ca(const T &v,char): elem{v} { } // OK - ca(const T &v,double): elem({v}) { } // { dg-error "paren" } + ca(const T &v,double): elem({v}) { } // { dg-error "paren" "" { target { ! c++20 } } } }; int main() { diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init33.C b/gcc/testsuite/g++.dg/cpp2a/paren-init33.C new file mode 100644 index 00000000000..43f323e8f14 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init33.C @@ -0,0 +1,128 @@ +// PR c++/92812 +// { dg-do run { target c++20 } } +// { dg-options "-Wall -Wextra" } +// Initializing arrays in a member init list using ()-init, valid cases. + +#define assert(X) do { if (!(X)) __builtin_abort(); } while(0) + +struct S { int x, y; }; +struct N { int x, y; N(int, int); }; + +static S s{10, 11}; + +struct A { + S s1; + S s2; + S a1[2]; + S a2[2]; + S a3[2]; + S a4[2]; + S a5[2]; + S a6[2]; + A() : s1(1, 2), + s2(1), // { dg-warning "missing initializer for member" } + a1({1}), // { dg-warning "missing initializer for member" } + a2({1, 2}), + a3({}, {}), + a4(), + a5(s), + a6(s, s) + { } +}; + +struct C { + int a1[2]; + int a2[2]; + int a3[2]; + int a4[2]; + int a5[2]; + C() : a1(1), + a2(1, 2), + a3({1}), + a4({}, {}), + a5() + { } +}; + +struct D { + N n; + // Not an aggregate, should work pre-C++20 too. + D() : n(1, 2) { } +}; + +struct E { + char a1[4]; + char a2[4]; + E() : a1("ab"), + a2("abc") + { } +}; + +// Compound literal. +struct F { + F (); + S m[1]; +}; + +F::F () : m(__extension__(S[1]) { 1, 2 }) +{ +} + +struct B { int i; }; +struct Der : B { }; +Der d; +struct G { + B b1[1]; + B b2[2]; + G(): b1(d), + b2(d, d) + { } +}; + +// Variation of c++/93790. +struct Empty { }; +struct Empty_refwrap { + Empty& r; + Empty_refwrap(Empty &e) : r(e) { } + operator Empty&() { return r; } +}; + +Empty empty; +Empty_refwrap empty_refwrap(empty); + +struct H { + Empty &e; + // Turning this into {empty_refwrap} would break things. + H() : e(empty_refwrap) { } +}; + +int +main () +{ + A a; + assert (a.s1.x == 1 && a.s1.y == 2); + assert (a.s2.x == 1 && a.s2.y == 0); + assert (a.a1[0].x == 1 && a.a1[0].y == 0 + && a.a1[1].x == 0 && a.a1[1].y == 0); + assert (a.a2[0].x == 1 && a.a2[0].y == 2 + && a.a2[1].x == 0 && a.a2[1].y == 0); + assert (a.a3[0].x == 0 && a.a3[0].y == 0 + && a.a3[1].x == 0 && a.a3[1].y == 0); + assert (a.a4[0].x == 0 && a.a4[0].y == 0 + && a.a4[1].x == 0 && a.a4[1].y == 0); + assert (a.a5[0].x == 10 && a.a5[0].y == 11 + && a.a5[1].x == 0 && a.a5[1].y == 0); + assert (a.a6[0].x == 10 && a.a6[0].y == 11 + && a.a6[1].x == 10 && a.a6[1].y == 11); + + C c; + assert (c.a1[0] == 1 && c.a1[1] == 0); + assert (c.a2[0] == 1 && c.a2[1] == 2); + assert (c.a3[0] == 1 && c.a3[1] == 0); + assert (c.a4[0] == 0 && c.a4[1] == 0); + assert (c.a5[0] == 0 && c.a5[1] == 0); + + E e; + assert (__builtin_strcmp (e.a1, "ab") == 0 + && __builtin_strcmp (e.a2, "abc") == 0); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init34.C b/gcc/testsuite/g++.dg/cpp2a/paren-init34.C new file mode 100644 index 00000000000..24942764cb7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init34.C @@ -0,0 +1,25 @@ +// PR c++/92812 +// { dg-do compile { target c++20 } } +// Initializing arrays in a member init list using ()-init, invalid cases. + +struct S { int x, y; }; +struct N { int x, y; N(int, int); }; + +struct A { + N a[2]; + A() : a(1, 2) { } // { dg-error "could not convert" } +}; + +struct B { + S a[2]; + B() : a(1) // { dg-error "could not convert" } + { } +}; + +// Copy-initialization does not consider explicit ctors. +struct E { explicit E(int); }; + +struct C { + E a[2]; + C() : a(4, 5) { } // { dg-error "could not convert" } +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init35.C b/gcc/testsuite/g++.dg/cpp2a/paren-init35.C new file mode 100644 index 00000000000..4f1892742c4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init35.C @@ -0,0 +1,21 @@ +// PR c++/92812 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-Wno-psabi" } +// Paren-init in a member init list with vector types. + +typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__)); + +__m128 m; +__m128 g(m); +__m128 ag[](m, m, m); +__m128 ag2[]({}, {}, {}); + +struct A { + __m128 a1; + __m128 a2[2]; + __m128 a3[2]; + A() : a1(m), + a2(m, m), + a3({}, m) + { } +}; diff --git a/gcc/testsuite/g++.dg/diagnostic/mem-init1.C b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C index b749c72cd8b..8ea5264b0e0 100644 --- a/gcc/testsuite/g++.dg/diagnostic/mem-init1.C +++ b/gcc/testsuite/g++.dg/diagnostic/mem-init1.C @@ -4,7 +4,7 @@ struct A { A() : a() // { dg-error "reference type" } - , b(1) // { dg-error "incompatible" } + , b(1) // { dg-error "incompatible" "" { target { ! c++20 } } } , c(0) // { dg-bogus "" } {} @@ -17,7 +17,7 @@ template struct B { B() : a() // { dg-error "reference type" } - , b(1) // { dg-error "incompatible" } + , b(1) // { dg-error "incompatible" "" { target { ! c++20 } } } , c(0) // { dg-bogus "" } {} diff --git a/gcc/testsuite/g++.dg/init/array28.C b/gcc/testsuite/g++.dg/init/array28.C index 9869354279d..a75c36215f9 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 "" } + Goo() : x(Foo(4), Foo(5)) { } // { dg-error "" "" { target { ! c++20 } } } Foo x[2]; }; diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash60.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash60.C index a59d72a7bf6..1f5629b5134 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/crash60.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash60.C @@ -9,4 +9,4 @@ public: // Note that we mistakenly initialize the array data member as if it // was scalar -X::X () : f (0) {}// { dg-error "" } .* +X::X () : f (0) {}// { dg-error "" "" { target { ! c++20 } } } diff --git a/gcc/testsuite/g++.old-deja/g++.law/init10.C b/gcc/testsuite/g++.old-deja/g++.law/init10.C index 90e3e45d682..1a020ec730b 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/init10.C +++ b/gcc/testsuite/g++.old-deja/g++.law/init10.C @@ -20,7 +20,7 @@ public: b(); }; -b::b() : three(this) // { dg-error "array" } +b::b() : three(this) // { dg-error "array|could not convert" } { } diff --git a/gcc/testsuite/g++.old-deja/g++.other/array3.C b/gcc/testsuite/g++.old-deja/g++.other/array3.C index f89090f1747..6eeeb4f3888 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/array3.C +++ b/gcc/testsuite/g++.old-deja/g++.other/array3.C @@ -20,6 +20,7 @@ class B }; B::B (const A a[]) - : ary(a) // { dg-error "array" } + // { dg-error "could not convert|invalid conversion" "" { target { c++20 } } .+1 } + : ary(a) // { dg-error "array" "" { target { ! c++20 } } } { } base-commit: f049cda373d29ea1bce4065b24cbb392cdc5b172 -- 2.26.2