From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31720 invoked by alias); 29 Jun 2011 14:08:51 -0000 Received: (qmail 31709 invoked by uid 22791); 29 Jun 2011 14:08:50 -0000 X-SWARE-Spam-Status: No, hits=-6.3 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_NV,TW_VF,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 29 Jun 2011 14:08:27 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p5TE8Rqv003583 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 29 Jun 2011 10:08:27 -0400 Received: from [127.0.0.1] (ovpn-113-39.phx2.redhat.com [10.3.113.39]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p5TE8QnU013003 for ; Wed, 29 Jun 2011 10:08:26 -0400 Message-ID: <4E0B31DA.4030308@redhat.com> Date: Wed, 29 Jun 2011 14:58:00 -0000 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b2 Thunderbird/3.1.10 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCHes to list-value-initialization Content-Type: multipart/mixed; boundary="------------020207040400070006000802" Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2011-06/txt/msg02244.txt.bz2 This is a multi-part message in MIME format. --------------020207040400070006000802 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 683 The first patch implements the resolution of DR 990, which clarifies that {} means value-initialization if the type has a default constructor. The second patch fixes a bug in the standard I noticed while looking at related issues: it says that if a class has any user-provided constructor, we just call the default constructor. This wording should have been adjusted when we added defaulted functions; I've raised the issue with the committee, but am also applying the obvious fix to the compiler, namely to only consider the user-providedness of the default constructor when deciding whether or not to zero-initialize first. Tested x86_64-pc-linux-gnu, applying to trunk. --------------020207040400070006000802 Content-Type: text/x-patch; name="value.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="value.patch" Content-length: 5159 commit 2bd88a2546673c5f10bedefff0dcfa3565d5b6fa Author: Jason Merrill Date: Tue Jun 28 10:20:50 2011 -0400 DR 990 * call.c (convert_like_real) [ck_user]: Handle value-initialization. (build_new_method_call_1): Likewise. * init.c (expand_default_init): Handle direct list-initialization of aggregates. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index cfaef7d..e2d455a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5592,6 +5592,18 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, tree convfn = cand->fn; unsigned i; + /* If we're initializing from {}, it's value-initialization. */ + if (BRACE_ENCLOSED_INITIALIZER_P (expr) + && CONSTRUCTOR_NELTS (expr) == 0 + && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype)) + { + expr = build_value_init (totype, complain); + expr = get_target_expr_sfinae (expr, complain); + if (expr != error_mark_node) + TARGET_EXPR_LIST_INIT_P (expr) = true; + return expr; + } + expr = mark_rvalue_use (expr); /* When converting from an init list we consider explicit @@ -5634,7 +5646,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, { int nelts = CONSTRUCTOR_NELTS (expr); if (nelts == 0) - expr = build_value_init (totype, tf_warning_or_error); + expr = build_value_init (totype, complain); else if (nelts == 1) expr = CONSTRUCTOR_ELT (expr, 0)->value; else @@ -7138,10 +7150,29 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args, && BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *args, 0)) && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0))) { + tree init_list = VEC_index (tree, *args, 0); + gcc_assert (VEC_length (tree, *args) == 1 && !(flags & LOOKUP_ONLYCONVERTING)); - add_list_candidates (fns, first_mem_arg, VEC_index (tree, *args, 0), + /* If the initializer list has no elements and T is a class type with + a default constructor, the object is value-initialized. Handle + this here so we don't need to handle it wherever we use + build_special_member_call. */ + if (CONSTRUCTOR_NELTS (init_list) == 0 + && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype) + && !processing_template_decl) + { + tree ob, init = build_value_init (basetype, complain); + if (integer_zerop (instance_ptr)) + return get_target_expr_sfinae (init, complain); + ob = build_fold_indirect_ref (instance_ptr); + init = build2 (INIT_EXPR, TREE_TYPE (ob), ob, init); + TREE_SIDE_EFFECTS (init) = true; + return init; + } + + add_list_candidates (fns, first_mem_arg, init_list, basetype, explicit_targs, template_only, conversion_path, access_binfo, flags, &candidates); } @@ -8365,7 +8396,7 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain) permitted. If the conversion is valid, the converted expression is returned. Otherwise, NULL_TREE is returned, except in the case that TYPE is a class type; in that case, an error is issued. If - C_CAST_P is true, then this direction initialization is taking + C_CAST_P is true, then this direct-initialization is taking place as part of a static_cast being attempted as part of a C-style cast. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 3ceed90..1719339 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1443,6 +1443,17 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, tree rval; VEC(tree,gc) *parms; + /* If we have direct-initialization from an initializer list, pull + it out of the TREE_LIST so the code below can see it. */ + if (init && TREE_CODE (init) == TREE_LIST + && BRACE_ENCLOSED_INITIALIZER_P (TREE_VALUE (init)) + && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init))) + { + gcc_checking_assert ((flags & LOOKUP_ONLYCONVERTING) == 0 + && TREE_CHAIN (init) == NULL_TREE); + init = TREE_VALUE (init); + } + if (init && BRACE_ENCLOSED_INITIALIZER_P (init) && CP_AGGREGATE_TYPE_P (type)) { diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist4.C new file mode 100644 index 0000000..8151857 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist4.C @@ -0,0 +1,8 @@ +// { dg-options -std=c++0x } + +struct A { int i; }; +struct B: A { constexpr B(): A{} {} }; +struct B2: A { constexpr B2(): A{1} {} }; + +struct C { protected: int i; }; +struct D: C { constexpr D(): C{} {} }; diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-value.C b/gcc/testsuite/g++.dg/cpp0x/initlist-value.C new file mode 100644 index 0000000..25a3373 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-value.C @@ -0,0 +1,26 @@ +// Test for value-initialization via {} +// { dg-options -std=c++0x } +// { dg-do run } + +// Empty base so A isn't an aggregate +struct B {}; +struct A: B { + int i; +}; + +struct C: A { + C(): A{} {} +}; + +int f(A a) { return a.i; } + +int main() +{ + A a{}; + C c; + if (a.i != 0 + || c.i != 0 + || A{}.i != 0 + || f({}) != 0) + return 1; +} --------------020207040400070006000802 Content-Type: text/x-patch; name="value2.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="value2.patch" Content-length: 2307 commit 900881b6124897c0384ee970fde989785ddaf49e Author: Jason Merrill Date: Tue Jun 28 17:25:40 2011 -0400 * init.c (build_value_init): Decide whether or not to zero-initialize based on user-providedness of default ctor, not any ctor. (build_value_init_noctor): Adjust assert. diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1719339..ac2b733 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -334,14 +334,20 @@ build_value_init (tree type, tsubst_flags_t complain) if (CLASS_TYPE_P (type)) { - if (type_has_user_provided_constructor (type)) + /* Instead of the above, only consider the user-providedness of the + default constructor itself so value-initializing a class with an + explicitly defaulted default constructor and another user-provided + constructor works properly (c++std-core-19883). */ + if (type_has_user_provided_default_constructor (type) + || (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type) + && type_has_user_provided_constructor (type))) return build_aggr_init_expr (type, build_special_member_call (NULL_TREE, complete_ctor_identifier, NULL, type, LOOKUP_NORMAL, complain), complain); - else if (type_build_ctor_call (type)) + else if (TYPE_HAS_COMPLEX_DFLT (type)) { /* This is a class that needs constructing, but doesn't have a user-provided constructor. So we need to zero-initialize @@ -371,7 +377,7 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) SFINAE-enabled. */ if (CLASS_TYPE_P (type)) { - gcc_assert (!type_build_ctor_call (type)); + gcc_assert (!TYPE_HAS_COMPLEX_DFLT (type)); if (TREE_CODE (type) != UNION_TYPE) { diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-value2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-value2.C new file mode 100644 index 0000000..2b78241 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-value2.C @@ -0,0 +1,20 @@ +// Test that we properly value-initialize a class with a user-provided +// constructor but defaulted default constructor. The FDIS got this +// wrong; see c++std-core-19883. + +// { dg-options -std=c++0x } +// { dg-do run } + +struct A +{ + int i; + A() = default; + A(int); +}; + +int main() +{ + A a{}; + if (a.i != 0) + return 1; +} --------------020207040400070006000802--