From patchwork Fri Sep 23 22:17:15 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 116184 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 48CBDB6F7C for ; Sat, 24 Sep 2011 08:17:40 +1000 (EST) Received: (qmail 20977 invoked by alias); 23 Sep 2011 22:17:37 -0000 Received: (qmail 20968 invoked by uid 22791); 23 Sep 2011 22:17:36 -0000 X-SWARE-Spam-Status: No, hits=-6.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS 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; Fri, 23 Sep 2011 22:17:18 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p8NMHHHx021795 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 23 Sep 2011 18:17:17 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p8NMHGrJ020928 for ; Fri, 23 Sep 2011 18:17:17 -0400 Received: from [0.0.0.0] (ovpn-113-83.phx2.redhat.com [10.3.113.83]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p8NMHFM7013020 for ; Fri, 23 Sep 2011 18:17:16 -0400 Message-ID: <4E7D056B.3090407@redhat.com> Date: Fri, 23 Sep 2011 18:17:15 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:6.0.2) Gecko/20110906 Thunderbird/6.0.2 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for core issue 253: const objects and explicit initializers Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Issue 253 was raised in 2000, but was considered low priority at the time; it pointed out that classes with no actual data don't really need an initializer, so we shouldn't require one. This becomes more important now that we have non-static data member initializers that can initialize all the members without a user-provided constructor. Tested x86_64-pc-linux-gnu, applied to trunk. I'm also considering applying it to 4.6 since we got more strict about the pre-253 rule in 4.6. commit f8bbf6bb2853ef073807b5e275fa40edae3d8aa0 Author: Jason Merrill Date: Thu Sep 15 17:15:34 2011 -0400 Core 253 - allow const objects with no initializer or user-provided default constructor if the defaulted constructor initializes all the subobjects. PR c++/20039 PR c++/42844 * class.c (default_init_uninitialized_part): New. * cp-tree.h: Declare it. * decl.c (check_for_uninitialized_const_var): Use it. * init.c (perform_member_init): Likewise. (build_new_1): Likewise. * method.c (walk_field_subobs): Likewise. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index e398416..1887526 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4356,6 +4356,40 @@ type_has_user_provided_default_constructor (tree t) return false; } +/* If default-initialization leaves part of TYPE uninitialized, returns + a DECL for the field or TYPE itself (DR 253). */ + +tree +default_init_uninitialized_part (tree type) +{ + tree t, r, binfo; + int i; + + type = strip_array_types (type); + if (!CLASS_TYPE_P (type)) + return type; + if (type_has_user_provided_default_constructor (type)) + return NULL_TREE; + for (binfo = TYPE_BINFO (type), i = 0; + BINFO_BASE_ITERATE (binfo, i, t); ++i) + { + r = default_init_uninitialized_part (BINFO_TYPE (t)); + if (r) + return r; + } + for (t = TYPE_FIELDS (type); t; t = DECL_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL + && !DECL_ARTIFICIAL (t) + && !DECL_INITIAL (t)) + { + r = default_init_uninitialized_part (TREE_TYPE (t)); + if (r) + return DECL_P (r) ? r : t; + } + + return NULL_TREE; +} + /* Returns true iff for class T, a trivial synthesized default constructor would be constexpr. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bcfc3b3..573c166 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4838,6 +4838,7 @@ extern tree in_class_defaulted_default_constructor (tree); extern bool user_provided_p (tree); extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_default_constructor (tree); +extern tree default_init_uninitialized_part (tree); extern bool trivial_default_constructor_is_constexpr (tree); extern bool type_has_constexpr_default_constructor (tree); extern bool type_has_virtual_destructor (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 709deca..495d8a0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4899,15 +4899,16 @@ check_for_uninitialized_const_var (tree decl) if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (type) != REFERENCE_TYPE && CP_TYPE_CONST_P (type) - && (!TYPE_NEEDS_CONSTRUCTING (type) - || !type_has_user_provided_default_constructor (type)) && !DECL_INITIAL (decl)) { + tree field = default_init_uninitialized_part (type); + if (!field) + return; + permerror (DECL_SOURCE_LOCATION (decl), "uninitialized const %qD", decl); - if (CLASS_TYPE_P (type) - && !type_has_user_provided_default_constructor (type)) + if (CLASS_TYPE_P (type)) { tree defaulted_ctor; @@ -4918,6 +4919,8 @@ check_for_uninitialized_const_var (tree decl) inform (DECL_SOURCE_LOCATION (defaulted_ctor), "constructor is not user-provided because it is " "explicitly defaulted in the class body"); + inform (0, "and the implicitly-defined constructor does not " + "initialize %q+#D", field); } } } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index ff1884b..68d4e68 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -579,7 +579,7 @@ perform_member_init (tree member, tree init) flags |= LOOKUP_DEFAULTED; if (CP_TYPE_CONST_P (type) && init == NULL_TREE - && !type_has_user_provided_default_constructor (type)) + && default_init_uninitialized_part (type)) /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a vtable; still give this diagnostic. */ permerror (DECL_SOURCE_LOCATION (current_function_decl), @@ -2088,7 +2088,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, } if (CP_TYPE_CONST_P (elt_type) && *init == NULL - && !type_has_user_provided_default_constructor (elt_type)) + && default_init_uninitialized_part (elt_type)) { if (complain & tf_error) error ("uninitialized const in % of %q#T", elt_type); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 5b24f8f..757e711 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1015,8 +1015,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, { bool bad = true; if (CP_TYPE_CONST_P (mem_type) - && (!CLASS_TYPE_P (mem_type) - || !type_has_user_provided_default_constructor (mem_type))) + && default_init_uninitialized_part (mem_type)) { if (msg) error ("uninitialized non-static const member %q#D", diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C index 3af8509..4ff398b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C @@ -7,7 +7,7 @@ // p 1 constexpr specifier // objects, static const data -struct A1 { }; // { dg-message "no user-provided default constructor" } +struct A1 { int i; }; // { dg-message "no user-provided default constructor" } constexpr int i1 = 1024; constexpr A1 a1 = A1(); diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted2.C b/gcc/testsuite/g++.dg/cpp0x/defaulted2.C index 1f400f4..e3aac8f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/defaulted2.C +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted2.C @@ -17,7 +17,8 @@ void g() = delete; // { dg-error "redefinition" } struct B // { dg-message "user-provided default constructor" } { - B() = default; // { dg-message "not user-provided" } + int i; + B() = default; // { dg-message "not user-provided" } }; const B b; // { dg-error "uninitialized const" } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C b/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C index 5af4ff2..4425aac 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C @@ -4,6 +4,7 @@ struct A // { dg-message "user-provided default constructor" } { + int i; A() = default; // { dg-message "not user-provided" } }; @@ -14,17 +15,20 @@ struct Base struct Derived : Base // { dg-message "user-provided default constructor" } { + int i; Derived() = default; // { dg-message "not user-provided" } }; struct Derived2 : Base // { dg-message "user-provided default constructor" } { + int i; Derived2() = default; // { dg-message "not user-provided" } Derived2( Derived2 const& ) = default; }; struct Derived3 : Base // { dg-message "user-provided default constructor" } { + int i; Derived3( Derived3 const& ) = default; Derived3() = default; // { dg-message "not user-provided" } }; diff --git a/gcc/testsuite/g++.dg/init/const8.C b/gcc/testsuite/g++.dg/init/const8.C new file mode 100644 index 0000000..4eb293d --- /dev/null +++ b/gcc/testsuite/g++.dg/init/const8.C @@ -0,0 +1,11 @@ +// DR 234 - it should be OK to leave off the initializer of a const +// variable if the default constructor fully initializes the object. + +struct A { }; +const A a; + +struct B { A a; }; +const B b; + +struct C { virtual void f(); }; +const C c; diff --git a/gcc/testsuite/g++.dg/init/pr20039.C b/gcc/testsuite/g++.dg/init/pr20039.C index 9b0c12d..aaac8bd 100644 --- a/gcc/testsuite/g++.dg/init/pr20039.C +++ b/gcc/testsuite/g++.dg/init/pr20039.C @@ -10,6 +10,7 @@ struct M struct X { M m; + int i; }; int mymain() diff --git a/gcc/testsuite/g++.dg/init/pr42844.C b/gcc/testsuite/g++.dg/init/pr42844.C index 7b423cc..299a30a 100644 --- a/gcc/testsuite/g++.dg/init/pr42844.C +++ b/gcc/testsuite/g++.dg/init/pr42844.C @@ -6,19 +6,19 @@ struct A A(){} }; -struct B : A {}; // { dg-message "user-provided default constructor" } +struct B : A { int i; }; // { dg-message "user-provided default constructor" } -struct C : A {}; // { dg-message "user-provided default constructor" } +struct C : A { int i; }; // { dg-message "user-provided default constructor" } struct D : B { D() {} }; -struct E {}; // { dg-message "user-provided default constructor" } +struct E { int i; }; // { dg-message "user-provided default constructor" } template -struct F : A {}; // { dg-message "user-provided default constructor" } +struct F : A { T t; }; // { dg-message "user-provided default constructor" } template -struct G {}; // { dg-message "user-provided default constructor" } +struct G { T t; }; // { dg-message "user-provided default constructor" } void f () { @@ -41,9 +41,9 @@ void f () extern G const gext; } -struct H {}; // { dg-message "user-provided default constructor" } +struct H { int i; }; // { dg-message "user-provided default constructor" } -struct I : A {}; // { dg-message "user-provided default constructor" } +struct I : A { int i; }; // { dg-message "user-provided default constructor" } template void g ()