From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id C74303858400 for ; Sat, 27 Nov 2021 22:56:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C74303858400 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-194-ztRvBjKYNCaFVzceusmIdA-1; Sat, 27 Nov 2021 17:56:29 -0500 X-MC-Unique: ztRvBjKYNCaFVzceusmIdA-1 Received: by mail-qt1-f200.google.com with SMTP id h20-20020ac85e14000000b002b2e9555bb1so13732544qtx.3 for ; Sat, 27 Nov 2021 14:56:29 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:subject :content-language:to:references:from:in-reply-to :content-transfer-encoding; bh=2fd8IC3pEGUbnQUA8/VqZ2tu5Y9VfJME/CN8VpDhouA=; b=45Fni4mQ7qaa9WC/SG/ijofYK5eVKV7AN+9WOzGEVEcTfSk7LXzuYq+Kk6gDL+MTjE uJrstW+F134Nbs+tcseEu4kRiWRhZRnW2kjx7CmmsTUCZrhvKPX6IXK9vCylnvj0tJ+E /R9AhGKGZmZ98r3S+f48Lfj8T7DmmAfqz/ibHY6+X7kby+gZrCipcQQx+WrWuUs61Ub5 XZfL/QDRomyclZphZqnRLqOqgFN4OPZ6auZM2yuAxJSNQQ34yHsgeMQk74gNdMuRdk1t D+IauRyYJj367QGKYkJh0FKJKFwKg0e3ibRkVc8+yizXAS8c5fnj3QOWKdivbfc7CCrg F4fQ== X-Gm-Message-State: AOAM533wFMoIsAJE1F7hmYlysG1xOYRF+eevNbfD9d3Y1d/vg0/B49G3 zmbtLvjRz3nSQ5MFOo5wEGPz9Eq5w052rHhjGcjO/XRc5dIwv+vL2UeMisUoAD2RWlXypA3ByiD EmsLv+zh2JGSrKh6SmA== X-Received: by 2002:a05:622a:1196:: with SMTP id m22mr35806613qtk.290.1638053788329; Sat, 27 Nov 2021 14:56:28 -0800 (PST) X-Google-Smtp-Source: ABdhPJz8w3/JqNDaT0zthrTpN47ofu5WMPh0yNCBTKohofTBtbBMpR1k43aCpvqWuS1sPGL8RVA7kg== X-Received: by 2002:a05:622a:1196:: with SMTP id m22mr35806572qtk.290.1638053787622; Sat, 27 Nov 2021 14:56:27 -0800 (PST) Received: from [192.168.1.149] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id i14sm5631906qko.9.2021.11.27.14.56.26 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 27 Nov 2021 14:56:26 -0800 (PST) Message-ID: <906dd866-f769-25d2-dea0-b17c59c0dadb@redhat.com> Date: Sat, 27 Nov 2021 17:56:24 -0500 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.3.2 Subject: Re: [PATCH 2/3] c++: P1997 array-copy extensions: Initialization [PR103238] To: Will Wray , gcc-patches@gcc.gnu.org References: <20211122025114.3167997-1-wjwray@gmail.com> <20211122025114.3167997-3-wjwray@gmail.com> From: Jason Merrill In-Reply-To: <20211122025114.3167997-3-wjwray@gmail.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: Sat, 27 Nov 2021 22:56:37 -0000 On 11/21/21 21:51, Will Wray via Gcc-patches wrote: > This patch implements initializations of arrays from array values. > > The first of two 'array-copy' patches, it adds the option -farray-copy > (flag_array_copy) to enable all features of P1997 (copy related or not), > documented as experimental extensions. > > It deals with initialization of array variables and member array fields. > > Initialization of an array variable from an array of the same type performs > array copy-initialization; elementwise move or copy from an rvalue or lvalue > array respectively, in index order from begin to end. The existing code path > for a structured binding declaration with array initializer, auto[e...]{a}; > performs the same array copy-initialization (as a special case superpower). > Borrowing from that, this was a relatively quick and easy change. > > Initialization of member arrays proved much more difficult to do in general. > I resorted to trial and error, running gcc in gdb with test cases to work out > where and what to change, until eventually converging on this set of changes. > > One starting point was the C special case of char array initialization from > string literals (as char array lvalue constants). However, a long-standing > bug in designated initialization of char arrays by string literals blocked > the task of extending this special case to general array type initializers. > A bugfix patch was separated out, to be merged ahead of these patches: > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55227 > https://gcc.gnu.org/pipermail/gcc-patches/2021-November/584897.html > > Other cases to consider, array initializations: > > * by optionally brace-enclosed or paren-enclosed array values > * by possibly-designated array-valued aggregate initializers > (within possibly-elided braced init-lists) > * by brace or paren-enclosed array values in member initialization lists > * by array-valued member initializers > > The patch adds tests for these cases, and for inner initializations of nested > array elements of array type. > > The work has diverged in details from the P1997 wording, including catching > up with C++20 changes such as parenthesised initialization of aggregates. > The paper will be revised to reflect the implementation experience. > > It is likely that there are omissions, errors in the conditions or that changed > code is inappropriate. For example, I inserted a new call to build_array_copy > in typeck2.c:digest_init_r which may not be correct for move-enabled elements. > Please review carefully with this in mind and suggest test cases to exercise. You would want a testcase with an array of move-only type, e.g. (untested) struct A { A(int); A(A&&); int i; }; using Ar = A[2]; struct B { A a[2]; }; B b = { Ar{1,2} }; // should move I don't think the new call to build_array_copy needs to change, but it's good to test. > PR c++/103238 > > gcc/c-family/ChangeLog: > > * c-common.c (complete_array_type): Accept array type initial_value. > * c.opt: New option -farray-copy "experimental extensions for P1997". > > gcc/cp/ChangeLog: > > * decl.c (do_aggregate_paren_init): Accept single array type init. > (maybe_deduce_size_from_array_init): Include same-type array inits, > or complain for not same-type arrays. > (reshape_init_r): Extend string-literal handling to all array types. > * init.c (build_aggr_init): Follow existing path for array rhs. > * typeck.c (cp_build_modify_expr): Follow path for synthetic op=. > * typeck2.c (digest_init_r): Add call to build_array_copy for > same-type arrays ('copy' feels wrong for move-eligible rhs). > > gcc/ChangeLog: > > * doc/invoke.texi: -farray-copy help info documentation. > > gcc/testsuite/ChangeLog: > > * g++.dg/init/array-copy1.C: New test. Variable init 'before' XFAILs > * g++.dg/init/array-copy2.C: New test. Variable init 'after' PASSes > * g++.dg/init/array-copy3.C: New test. Member init 'before' XFAILs > * g++.dg/init/array-copy4.C: New test. Member init 'after' PASSes > * g++.dg/init/array-copy5.C: New test. Member nsdmi & desig XFAILs > * g++.dg/init/array-copy6.C: New test. Member nsdmi & desig PASSes > --- > gcc/c-family/c-common.c | 5 +++ > gcc/c-family/c.opt | 4 ++ > gcc/cp/decl.c | 61 ++++++++++++++++++++--------- > gcc/cp/init.c | 6 ++- > gcc/cp/typeck.c | 9 +++-- > gcc/cp/typeck2.c | 30 +++++++++++---- > gcc/doc/invoke.texi | 6 +++ > gcc/testsuite/g++.dg/init/array-copy1.C | 66 ++++++++++++++++++++++++++++++++ > gcc/testsuite/g++.dg/init/array-copy2.C | 68 +++++++++++++++++++++++++++++++++ > gcc/testsuite/g++.dg/init/array-copy3.C | 41 ++++++++++++++++++++ > gcc/testsuite/g++.dg/init/array-copy4.C | 42 ++++++++++++++++++++ > gcc/testsuite/g++.dg/init/array-copy5.C | 36 +++++++++++++++++ > gcc/testsuite/g++.dg/init/array-copy6.C | 51 +++++++++++++++++++++++++ > 13 files changed, 395 insertions(+), 30 deletions(-) > > diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c > index 86c007f53de..fb0b1ef294f 100644 > --- a/gcc/c-family/c-common.c > +++ b/gcc/c-family/c-common.c > @@ -6796,6 +6796,11 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default) > = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value))); > maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1); > } > + else if (flag_array_copy > + && TREE_CODE (TREE_TYPE (initial_value)) == ARRAY_TYPE) > + { > + maxindex = array_type_nelts (TREE_TYPE (initial_value)); > + } > else if (TREE_CODE (initial_value) == CONSTRUCTOR) > { > vec *v = CONSTRUCTOR_ELTS (initial_value); > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > index 3976fc368db..9d2a6ad8e1c 100644 > --- a/gcc/c-family/c.opt > +++ b/gcc/c-family/c.opt > @@ -1579,6 +1579,10 @@ fcilkplus > C ObjC C++ ObjC++ LTO Undocumented Ignore > Removed in GCC 8. This switch has no effect. > > +farray-copy > +C ObjC C++ ObjC++ Var(flag_array_copy) > +Enable experimental extension for P1997; C array copy semantics. > + > fconcepts > C++ ObjC++ Var(flag_concepts) > Enable support for C++ concepts. > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c > index 83a2d3bf8f1..1010fa2c53f 100644 > --- a/gcc/cp/decl.c > +++ b/gcc/cp/decl.c > @@ -5834,15 +5834,19 @@ tree > do_aggregate_paren_init (tree init, tree type) > { > tree val = TREE_VALUE (init); > + tree stripped_val = tree_strip_any_location_wrapper (val); > > if (TREE_CHAIN (init) == NULL_TREE) > { > /* If the list has a single element and it's a string literal, > then it's the initializer for the array as a whole. */ > - if (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 ((TREE_CODE (type) == ARRAY_TYPE > + && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) > + && TREE_CODE (stripped_val) == STRING_CST) > + || (flag_array_copy > + && TREE_CODE (TREE_TYPE (stripped_val)) == ARRAY_TYPE > + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type), > + TREE_TYPE (TREE_TYPE (stripped_val))))) > return val; > /* Handle non-standard extensions like compound literals. This also > prevents triggering aggregate parenthesized-initialization in > @@ -6007,9 +6011,10 @@ maybe_deduce_size_from_array_init (tree decl, tree init) > { > tree type = TREE_TYPE (decl); > > - if (TREE_CODE (type) == ARRAY_TYPE > - && TYPE_DOMAIN (type) == NULL_TREE > - && TREE_CODE (decl) != TYPE_DECL) > + if (TREE_CODE (type) != ARRAY_TYPE > + || TREE_CODE (decl) == TYPE_DECL) > + ; > + else if (TYPE_DOMAIN (type) == NULL_TREE) > { > /* do_default is really a C-ism to deal with tentative definitions. > But let's leave it here to ease the eventual merge. */ > @@ -6072,6 +6077,17 @@ maybe_deduce_size_from_array_init (tree decl, tree init) > > relayout_decl (decl); > } > + else if (flag_array_copy && init > + && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE > + && TREE_CODE (tree_strip_any_location_wrapper (init)) != STRING_CST > + && !same_type_ignoring_top_level_qualifiers_p (type, > + TREE_TYPE (init))) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "array of type %qT cannot be initialized with an " > + "array of type %qT in %qD", type, TREE_TYPE (init), decl); > + TREE_TYPE (decl) = error_mark_node; > + } > } > > /* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue > @@ -6815,21 +6831,23 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, > return init; > } > > - /* [dcl.init.string] > + /* [dcl.init.string] or flag_array_copy extension P1997 > > A char array (whether plain char, signed char, or unsigned char) > can be initialized by a string-literal (optionally enclosed in > braces); a wchar_t array can be initialized by a wide > - string-literal (optionally enclosed in braces). */ > - if (TREE_CODE (type) == ARRAY_TYPE > - && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))) > + string-literal (optionally enclosed in braces). > + With flag_array_copy an array can be initialized by an array value > + (optionally enclosed in braces). */ > + if (TREE_CODE (type) == ARRAY_TYPE) > { > tree arr_init = init; > tree stripped_arr_init = stripped_init; The renaming belongs in this patch. > reshape_iter stripd = {}; > > - /* Strip one level of braces if and only if they enclose a single > - element (as allowed by [dcl.init.string]). */ > + /* Strip one level of braces if they enclose a single element, > + provisionally for elison in the optionally-braced case if the > + initializer is of compatible array type, as checked next. */ > if (!first_initializer_p > && TREE_CODE (stripped_arr_init) == CONSTRUCTOR > && CONSTRUCTOR_NELTS (stripped_arr_init) == 1) > @@ -6839,10 +6857,19 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, > stripped_arr_init = tree_strip_any_location_wrapper (arr_init); > } > > - /* If it's a string literal, then it's the initializer for the array > - as a whole. Otherwise, continue with normal initialization for > - array types (one value per array element). */ > - if (TREE_CODE (stripped_arr_init) == STRING_CST) > + tree init_type = TREE_TYPE (stripped_arr_init); > + > + /* If it's a string literal initializer for a char array target, > + or, with flag_array_copy, an array value of same element type, > + then it's the initializer for the array as a whole. > + Else, continue with element by element array initialization. */ > + if ((TREE_CODE (stripped_arr_init) == STRING_CST > + && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))) > + || (flag_array_copy > + && TREE_CODE (init_type) == ARRAY_TYPE > + && TYPE_DOMAIN (init_type) != NULL_TREE > + && same_type_ignoring_top_level_qualifiers_p ( > + TREE_TYPE (type), TREE_TYPE (init_type)))) > { > if ((first_initializer_p && has_designator_problem (d, complain)) > || (stripd.cur && has_designator_problem (&stripd, complain))) > diff --git a/gcc/cp/init.c b/gcc/cp/init.c > index 3ba2e3bbe04..fd9a065ed95 100644 > --- a/gcc/cp/init.c > +++ b/gcc/cp/init.c > @@ -1787,7 +1787,11 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain) > tree itype = init ? TREE_TYPE (init) : NULL_TREE; > int from_array = 0; > > - if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp)) > + if (VAR_P (exp) > + && (DECL_DECOMPOSITION_P (exp) > + || (flag_array_copy > + && TREE_CODE (tree_strip_any_location_wrapper (init)) > + != STRING_CST))) > { > from_array = 1; > init = mark_rvalue_use (init); > diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c > index cb20329ceb5..8e96a925186 100644 > --- a/gcc/cp/typeck.c > +++ b/gcc/cp/typeck.c > @@ -9144,11 +9144,12 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, > } > > /* Allow array assignment in compiler-generated code. */ > - else if (!current_function_decl > - || !DECL_DEFAULTED_FN (current_function_decl)) > + else if ((!current_function_decl > + || !DECL_DEFAULTED_FN (current_function_decl)) > + && !flag_array_copy) > { > - /* This routine is used for both initialization and assignment. > - Make sure the diagnostic message differentiates the context. */ > + /* This routine is used for both initialization and assignment. > + Make sure the diagnostic message differentiates the context. */ > if (complain & tf_error) > { > if (modifycode == INIT_EXPR) > diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c > index e98fbf7f5fa..20d46716279 100644 > --- a/gcc/cp/typeck2.c > +++ b/gcc/cp/typeck2.c > @@ -1175,6 +1175,9 @@ digest_init_r (tree type, tree init, int nested, int flags, > } > return init; > } > + if (flag_array_copy > + && same_type_ignoring_top_level_qualifiers_p(type, TREE_TYPE (init))) > + return build_array_copy(init); Missing space before ( on two lines. > } > > /* Handle scalar types (including conversions) and references. */ > @@ -1244,13 +1247,18 @@ digest_init_r (tree type, tree init, int nested, int flags, > complain); > else > { > - if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE) > + if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE > + && (complain & tf_error)) > { > - if (complain & tf_error) > - error_at (loc, "cannot initialize aggregate of type %qT with " > - "a compound literal", type); > - > - return error_mark_node; > + if (flag_array_copy) > + pedwarn (loc, OPT_Wpedantic, "ISO C++ doesn%'t allow initialization" > + "of an array of type %qT with a compound literal", type); > + else > + { > + error_at (loc, "cannot initialize aggregate of type %qT with " > + "a compound literal", type); > + return error_mark_node; > + } This changes the function to only return error_mark_node when we're diagnosing errors, which seems wrong; we need it to fail in SFINAE context as well. > } > > if (code == ARRAY_TYPE > @@ -1265,8 +1273,14 @@ digest_init_r (tree type, tree init, int nested, int flags, > return init; > > if (complain & tf_error) > - error_at (loc, "array must be initialized with a brace-enclosed" > - " initializer"); > + { > + if (!flag_array_copy) > + error_at (loc, "array must be initialized with a brace-enclosed" > + " initializer"); > + else > + error_at (loc, "array must be initialized with a brace-enclosed" > + " initializer or an array value of the same type"); > + } > return error_mark_node; > } > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index d62ec08150e..32a34ca74bb 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -213,6 +213,7 @@ in the following sections. > @xref{C++ Dialect Options,,Options Controlling C++ Dialect}. > @gccoptlist{-fabi-version=@var{n} -fno-access-control @gol > -faligned-new=@var{n} -fargs-in-order=@var{n} -fchar8_t -fcheck-new @gol > +-farray-copy @gol > -fconstexpr-depth=@var{n} -fconstexpr-cache-depth=@var{n} @gol > -fconstexpr-loop-limit=@var{n} -fconstexpr-ops-limit=@var{n} @gol > -fno-elide-constructors @gol > @@ -3001,6 +3002,11 @@ return value even without this option. In all other cases, when > exhaustion is signalled by throwing @code{std::bad_alloc}. See also > @samp{new (nothrow)}. > > +@item -farray-copy > +@opindex farray-copy > +Enables experimental support for P1997; C array copy semantics, pseudo- > +destructors and auto placeholder for array element type. > + > @item -fconcepts > @itemx -fconcepts-ts > @opindex fconcepts > diff --git a/gcc/testsuite/g++.dg/init/array-copy1.C b/gcc/testsuite/g++.dg/init/array-copy1.C > new file mode 100644 > index 00000000000..15986a00d1b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/init/array-copy1.C > @@ -0,0 +1,66 @@ > +// PR c++/103238 (array-copy extensions for P1997) > +// Array variable initialization nocompile tests - > +// should give same errors before and after the array-copy patch. > + > +// { dg-do compile { target c++11 } } c++11 for uniform init > + > +typedef int int2[2]; > +int2 u = {11,66}; > + > +int* p = new int2{u}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." } > + > +// Initializations from from rvalue array > +int2 g = int2{11,66}; > +int2 j ( int2{11,66} ); // takes P0960 paren-init path in c++20 > +int2 k = { int2{11,66} }; > +int2 l { int2{11,66} }; > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 } > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 } > +// { dg-error "taking address of temporary array" "address of temporary" { target *-*-* } .-4 } > +// { dg-error "taking address of temporary array" "address of temporary" { target *-*-* } .-4 } > + > +// Initializations from from lvalue array > +int2 gc = u; > +int2 jc (u); // takes P0960 paren-init path in c++20 > +int2 kc = {u}; > +int2 lc {u}; > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 } > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 } > +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-4 } > +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-4 } > + > +char str[] = "str"; > + > +char cpy[] = str; > +char cpp[] (str); // takes P0960 paren-init path in c++20 > +char cpu[] = {str}; > +char cpw[] {str}; > +// { dg-error "initializer fails to determine size of .cpy." "deduce size" { target *-*-* } .-4 } > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-5 } > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target c++17_down } .-5 } > +// { dg-error "initializer fails to determine size of .cpp." "deduce size" { target c++17_down } .-6 } > +// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target c++20 } .-7 } > +// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target *-*-* } .-7 } > +// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target *-*-* } .-7 } > + > +char cp5[5] = str; > +char cp3[3] = str; > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 } > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 } > + > +int2 s[2] = { u }; > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-1 } > +int2 x[2] = { u > + , u }; > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 } > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 } > +int2 y[2] = { 1,2 > + , {u} }; > +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-1 } > +int2 z[2] = { {u}, > + 3,{4} }; > +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-2 } > + > +__UINT8_TYPE__ m222[2][2][2] {0,1,2,3,4,5,6,7}; > +__UINT8_TYPE__ c222[2][2][2] { m222[0], m222[1][0], 6,7 }; > +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-1 } > diff --git a/gcc/testsuite/g++.dg/init/array-copy2.C b/gcc/testsuite/g++.dg/init/array-copy2.C > new file mode 100644 > index 00000000000..7e1ad23592b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/init/array-copy2.C > @@ -0,0 +1,68 @@ > +// PR c++/103238 (array-copy extensions for P1997) > +// Array variable initialization compile tests, -farray-copy enabled > +// (c.f. array-copy1.C for compile fail tests) > + > +// { dg-do compile { target c++11 } } c++11 for uniform init > +// { dg-additional-options "-farray-copy" } > + > +typedef int int2[2]; > +int2 u = {11,66}; > + > +int* p = new int2{u}; > + > +// Initializations from from rvalue array > +int2 g = int2{11,66}; > +int2 j ( int2{11,66} ); // takes P0960 paren-init path in c++20 > +int2 k = { int2{11,66} }; > +int2 l { int2{11,66} }; > + > +// Initializations from from lvalue array > +int2 gc = u; > +int2 jc (u); // takes P0960 paren-init path in c++20 > +int2 kc = {u}; > +int2 lc {u}; > + > +char str[] = "str"; > + > +char cpy[] = str; > +char cpp[] (str); // takes P0960 paren-init path in c++20 > +char cpu[] = {str}; > +char cpw[] {str}; > + > +char cp5[5] = str; > +char cp3[3] = str; > +// { dg-error "array of type .char .5.. cannot be initialized with an array of type .char .4.." "" { target *-*-* } .-2 } > +// { dg-error "array of type .char .3.. cannot be initialized with an array of type .char .4.." "" { target *-*-* } .-2 } > + > +constexpr char cstr[] = "str"; > +constexpr char ccpy[] = cstr; > +static_assert( > + __builtin_bit_cast(__UINT32_TYPE__, ccpy) > + == __builtin_bit_cast(__UINT32_TYPE__, "str") > +, "" > +); > + > +constexpr __UINT32_TYPE__ ci[] = {11,66}; > +constexpr __UINT32_TYPE__ cc[] = ci; > +static_assert( > + __builtin_bit_cast(__UINT64_TYPE__, ci) > + == __builtin_bit_cast(__UINT64_TYPE__, cc) > +, "" > +); > + > +int2 s[2] = { u }; > +int2 x[2] = { u > + , u }; > +int2 y[2] = { 1,2 > + , {u} }; > +int2 z[2] = { {u} > + , 3,{4} }; > + > +__UINT8_TYPE__ m222[2][2][2] {0,1,2,3,4,5,6,7}; > +__UINT8_TYPE__ c222[2][2][2] { m222[0], m222[1][0], 6,7 }; > + > +int main() { > + if (__builtin_bit_cast(__UINT64_TYPE__, m222) > + != __builtin_bit_cast(__UINT64_TYPE__, c222)) > + __builtin_abort (); > +} > diff --git a/gcc/testsuite/g++.dg/init/array-copy3.C b/gcc/testsuite/g++.dg/init/array-copy3.C > new file mode 100644 > index 00000000000..bec78cb8435 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/init/array-copy3.C > @@ -0,0 +1,41 @@ > +// PR c++/103238 (array-copy extensions for P1997) > +// Array member initialization nocompile tests - > +// should give same errors before and after the array-copy patch. > + > +// { dg-do compile { target c++11 } } c++11 for uniform init > +// > + > +typedef int int2[2]; > + > +struct A { int2 a; }; > + > +A ad { int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" } > +A ai = { int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" } > + > +struct B { int2 a, b, c, d; }; > + > +constexpr > +B b { > + {11,66} > + , {b.a} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." } > + , (b.b) // { dg-error "array must be initialized with a brace-enclosed initializer" } > + , b.c > +}; > + > +struct C { > + int2 a, b, c; > + C(const int2& r = {11,66}) > + : a{r} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." } > + , b(a) // { dg-error "array used as initializer" } > + , c{b} // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." } > + {} > +}; > + > +// Not a test; a workaround to construct a single array member from array > +struct D { > + int2 d; > + constexpr D(const int2& r = {}) > + : D{__builtin_bit_cast(D,r)} {} > +}; > +constexpr D d{{11,66}}; > +constexpr D e{b.a}; > diff --git a/gcc/testsuite/g++.dg/init/array-copy4.C b/gcc/testsuite/g++.dg/init/array-copy4.C > new file mode 100644 > index 00000000000..8db2852011a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/init/array-copy4.C > @@ -0,0 +1,42 @@ > +// PR c++/103238 (array-copy extensions for P1997) > +// Array member initialization compile tests - > +// (c.f. array-copy3.C for compile fail tests) > + > +// { dg-do compile { target c++11 } } c++11 for uniform init > +// { dg-additional-options "-farray-copy" } > + > +typedef int int2[2]; > + > +struct A { int2 a; }; > + > +A ad { int2{11,66} }; > +A ai = { int2{11,66} }; > + > +struct B { int2 a, b, c, d; }; > + > +constexpr > +B b { > + {11,66} > + , {b.a} > + , (b.b) > + , b.c > +}; > + > +struct C { > + int2 a, b, c; > + C(const int2& r = {11,66}) > + : a{r} > + , b(a) > + , c{b} > + {} > +}; > + > +template > +constexpr int equal(T const& a, T const& b) { > + using bytes = unsigned char[sizeof(T)]; > + return __builtin_memcmp( > + __builtin_bit_cast(bytes,a), > + __builtin_bit_cast(bytes,b), > + sizeof(T)) == 0; > +} > +static_assert( equal(b, B{{11,66},{11,66},{11,66},{11,66}}), ""); > diff --git a/gcc/testsuite/g++.dg/init/array-copy5.C b/gcc/testsuite/g++.dg/init/array-copy5.C > new file mode 100644 > index 00000000000..a3b6c275f2b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/init/array-copy5.C > @@ -0,0 +1,36 @@ > +// PR c++/103238 (array-copy extensions for P1997) > +// Array member initialization nocompile tests, nsdmi and designated init > +// should give same errors before and after the array-copy patch. > + > +// { dg-do compile { target c++14 } } c++14 for aggregate with member inits > +// { dg-options "" } > +// > + > +typedef int int2[2]; > + > +struct A { int2 a = int2{11,66}; }; // { dg-error "array must be initialized with a brace-enclosed initializer" } > + > +constexpr > +A a { .a = int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" } > +A y = { .a{int2{11,66}} }; // { dg-error "taking address of temporary array" } > + > +struct B { > + int2 a = {11,66}; > + int2 b = a; // { dg-error "array must be initialized with a brace-enclosed initializer" } > + int2 c = {b}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." } > + int2 d {c}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." } > +}; > + > +constexpr > +B b { > + {11,66} > + , {b.a} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." } > + , (b.b) // { dg-error "array must be initialized with a brace-enclosed initializer" } > + , b.c > +}; > + > +B bd { .a{11,66}, .b = bd.a, .c {bd.b}, .d = {bd.c} }; // { dg-error "array must be initialized with a brace-enclosed initializer" } > + > +struct D : A { > + B b {.a{11,66}, .b = b.a, .c {b.b}, .d = {b.c}}; // { dg-error "array must be initialized with a brace-enclosed initializer" } > +}; > diff --git a/gcc/testsuite/g++.dg/init/array-copy6.C b/gcc/testsuite/g++.dg/init/array-copy6.C > new file mode 100644 > index 00000000000..09b7478e07f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/init/array-copy6.C > @@ -0,0 +1,51 @@ > +// PR c++/103238 (array-copy extensions for P1997) > +// Array member initialization compile tests, nsdmi and designated init > +// (c.f. array-copy5.C for compile fail tests) > + > +// { dg-do compile { target c++20 } } > +// > +// { dg-additional-options "-farray-copy" } > + > +typedef int int2[2]; > + > +struct A { int2 a = int2{11,66}; }; > + > +constexpr > +A a { .a = int2{11,66} }; > +A y = { .a{int2{11,66}} }; > + > +struct B { > + int2 a = {11,66}; > + int2 b = a; > + int2 c = {b}; > + int2 d {c}; > +}; > + > +constexpr > +B b { > + {11,66} > + , {b.a} > + , (b.b) > + , b.c > +}; > + > +B bd { .a{11,66}, .b = bd.a, .c {bd.b}, .d = {bd.c} }; > + > +struct D : A { > + B b {.a{11,66}, .b = b.a, .c {b.b}, .d = {b.c}}; > +}; > + > +constexpr > +D d; > + > +template > +constexpr int equal(T const& a, T const& b) { > + using bytes = unsigned char[sizeof(T)]; > + return __builtin_memcmp( > + __builtin_bit_cast(bytes,a), > + __builtin_bit_cast(bytes,b), > + sizeof(T)) == 0; > +} > +static_assert( equal(b, B{}), ""); > +static_assert( equal(d, D{}), ""); > +static_assert( equal(d, D{a,b}), ""); >