From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by sourceware.org (Postfix) with ESMTP id DCD2A384243E for ; Wed, 2 Sep 2020 21:06:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org DCD2A384243E Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-424-KC4EIqaeNeu1gFoyFT4JBw-1; Wed, 02 Sep 2020 17:06:49 -0400 X-MC-Unique: KC4EIqaeNeu1gFoyFT4JBw-1 Received: by mail-qt1-f197.google.com with SMTP id w1so719815qto.4 for ; Wed, 02 Sep 2020 14:06:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=CkyciWacygGV5EnyTDr+qJkuiHckoKMCC9s36eyhasE=; b=HyY0iqTy71dXk9pqhDlz/ZhKyDZX1nqRYxmgLnORoWvnuG9MX3gvi/1CRMhLaM3QzW UMMPUUgJz2isZVwJTPvAEpM36eJK1AskSDoBbQdCAhPRIEikZxEwXQfV1YqNdtEwIpx8 +U0RyFK2OISoMNP3/YvL4U5h8TVwnSjqLbFKPfkSVExBzddwHy5dgEaYPrbmGoS3/faH /GnWnnDNjCChT70Vx7Tojpdxpl/CFYeUT3yjxrM0nZcin8JIR0d+M5Axh0mfRBOCgTKU ADl1z4hn02o4dfqaxTKm1gvQvwG9edV1EdlvASCBEM6WfWtl6+yhK3xyULlpRMssZw/6 3VSQ== X-Gm-Message-State: AOAM53041WLRgDotdc964IkH9TNdkm8drQ2kiGeHYIYI+zvRzLgJDAx7 9vKMGMLB0O2nVjF8eLlYqSrCo3AqRd1nq5JCo031MNLdn81oNY8doxEt7fBM2Xaj7FEomhWE6g8 IiP+RotJWjvtbv8Mk2g== X-Received: by 2002:ac8:3ac4:: with SMTP id x62mr116124qte.279.1599080807752; Wed, 02 Sep 2020 14:06:47 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy0SIHsypaluzFkLwlmQmRKTvK1WI+qwTB+p7xlS2GciWEsPT4zOhs43fM+MVWoyZJvYILyDg== X-Received: by 2002:ac8:3ac4:: with SMTP id x62mr116077qte.279.1599080807060; Wed, 02 Sep 2020 14:06:47 -0700 (PDT) Received: from [192.168.1.148] (209-6-216-142.s141.c3-0.smr-cbr1.sbo-smr.ma.cable.rcncustomer.com. [209.6.216.142]) by smtp.gmail.com with ESMTPSA id o25sm643884qkm.42.2020.09.02.14.06.46 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 02 Sep 2020 14:06:46 -0700 (PDT) Subject: Re: [PATCH v2] c++: Fix P0960 in member init list and array [PR92812] To: Marek Polacek Cc: GCC Patches References: <20200901222354.234729-1-polacek@redhat.com> <76109e86-fce4-00d4-8fba-f8f57df36da5@redhat.com> <20200902203749.GK5926@redhat.com> From: Jason Merrill Message-ID: Date: Wed, 2 Sep 2020 17:06:45 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.6.0 MIME-Version: 1.0 In-Reply-To: <20200902203749.GK5926@redhat.com> X-Mimecast-Spam-Score: 0.002 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-US X-Spam-Status: No, score=-16.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, 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 21:06:53 -0000 On 9/2/20 4:37 PM, Marek Polacek wrote: > 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, This condition: > + && (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)))))) seems like it could move into do_aggregate_paren_init as well, even if it's redundant with code in the caller in some cases; we never want to add { } to a single parenthesized expression of the same type. And don't we need to check for the same-type situation for the array case in check_initializer? Incidentally, for checking whether a list is length 1 or more, probably slightly more efficient to look at TREE_CHAIN directly like do_aggregate_paren_init does in this patch, rather than use list_length. Jason > 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 >