From patchwork Wed Jul 11 11:47:44 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 170439 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 AEE832C0204 for ; Wed, 11 Jul 2012 21:48:11 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1342612092; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Message-ID:Date:From:User-Agent:MIME-Version:To:Subject: References:In-Reply-To:Content-Type:Mailing-List:Precedence: List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=XYxCX33WSNW3YliG5GfUhXtuTsM=; b=J+q2uIcRE/eQV5a YlAYKiPN+9xbvXZmWHrC+m4neBqzYv6OLQ/OhsMv63bCU1FxDeQPNwi9s6hwIyI3 FIml/62Fedwn3uKaRfU/M9foEPSO3fTpyW1BDo46nwu0tdQ4V0yBFRCCNlV+0DBb GuiSgOowYZ5ycPHLnxJBSHMVVFW0= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:References:In-Reply-To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=g0AOuOng1tHE4chyjB1YdaEri6sGaqIp6H+F/mSGWN5NPrYYrbSyk6oywbRSRK rTu9fobTxjDA0i3XNrdtdTfvddHmh/DBaqTHP+A/9r4LdlZ0uuoMI+3AFzavur5t 9FOLVTZpjf3R6b9Y0uXCbeEK3VzWLKR+xhGdlOioiMt9E=; Received: (qmail 19810 invoked by alias); 11 Jul 2012 11:48:05 -0000 Received: (qmail 19746 invoked by uid 22791); 11 Jul 2012 11:48:02 -0000 X-SWARE-Spam-Status: No, hits=-7.1 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, KHOP_THREADED, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, SPF_HELO_PASS, 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, 11 Jul 2012 11:47:47 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q6BBllBE006738 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 11 Jul 2012 07:47:47 -0400 Received: from [10.36.116.74] (ovpn-116-74.ams2.redhat.com [10.36.116.74]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q6BBljrI005949 for ; Wed, 11 Jul 2012 07:47:45 -0400 Message-ID: <4FFD67E0.6040002@redhat.com> Date: Wed, 11 Jul 2012 13:47:44 +0200 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:13.0) Gecko/20120605 Thunderbird/13.0 MIME-Version: 1.0 To: gcc-patches List Subject: Re: C++ PATCH for c++/53733 (DR 1402, deleting move ctor) References: <4FFB71A5.3070800@redhat.com> In-Reply-To: <4FFB71A5.3070800@redhat.com> 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 On 07/10/2012 02:04 AM, Jason Merrill wrote: > Apparently we need to implement DR 1402 in 4.7 in order to fix the > std::pair ABI breakage properly. So here it is: if overload resolution > chooses a non-trivial copy constructor, instead of causing the move > constructor to be deleted, we just don't implicitly declare it. This is an incomplete implementation of (the current proposed resolution of) DR 1402, which also changes the conditions when a virtual base interferes with an implicitly-declared move assignment operator. This patch implements that, as well as some code cleanup. Tested x86_64-pc-linux-gnu, applying to trunk. commit 4295ec42ce03f2a4283c0e82d5cbdce681a68efa Author: Jason Merrill Date: Tue Jul 10 18:19:28 2012 +0200 DR 1402 * method.c (synthesized_method_walk): Replace uses of msg with diag. Correct handling of virtual bases with move operations. (process_subob_fn, walk_field_subobs): Replace uses of msg with diag. diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 79edf81..f3fd7b8 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -923,7 +923,7 @@ get_copy_assign (tree type) static void process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, bool *deleted_p, bool *constexpr_p, bool *no_implicit_p, - const char *msg, tree arg) + bool diag, tree arg) { if (!fn || fn == error_mark_node) goto bad; @@ -943,7 +943,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, { if (deleted_p) *deleted_p = true; - if (msg) + if (diag) error ("union member %q+D with non-trivial %qD", arg, fn); } } @@ -956,7 +956,7 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p, if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn)) { *constexpr_p = false; - if (msg) + if (diag) { inform (0, "defaulted constructor calls non-constexpr " "%q+D", fn); @@ -979,7 +979,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, int quals, bool copy_arg_p, bool move_p, bool assign_p, tree *spec_p, bool *trivial_p, bool *deleted_p, bool *constexpr_p, bool *no_implicit_p, - const char *msg, int flags, tsubst_flags_t complain) + bool diag, int flags, tsubst_flags_t complain) { tree field; for (field = fields; field; field = DECL_CHAIN (field)) @@ -996,13 +996,13 @@ 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)) { - if (msg) + if (diag) error ("non-static const member %q#D, can%'t use default " "assignment operator", field); } else if (TREE_CODE (mem_type) == REFERENCE_TYPE) { - if (msg) + if (diag) error ("non-static reference member %q#D, can%'t use " "default assignment operator", field); } @@ -1018,7 +1018,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, if (DECL_INITIAL (field)) { - if (msg && DECL_INITIAL (field) == error_mark_node) + if (diag && DECL_INITIAL (field) == error_mark_node) inform (0, "initializer for %q+#D is invalid", field); if (trivial_p) *trivial_p = false; @@ -1041,14 +1041,14 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, if (CP_TYPE_CONST_P (mem_type) && default_init_uninitialized_part (mem_type)) { - if (msg) + if (diag) error ("uninitialized non-static const member %q#D", field); bad = true; } else if (TREE_CODE (mem_type) == REFERENCE_TYPE) { - if (msg) + if (diag) error ("uninitialized non-static reference member %q#D", field); bad = true; @@ -1064,7 +1064,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, && TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE) { *constexpr_p = false; - if (msg) + if (diag) inform (0, "defaulted default constructor does not " "initialize %q+#D", field); } @@ -1078,7 +1078,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals, copy_arg_p, move_p, assign_p, spec_p, trivial_p, deleted_p, constexpr_p, no_implicit_p, - msg, flags, complain); + diag, flags, complain); continue; } @@ -1095,7 +1095,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk, rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - constexpr_p, no_implicit_p, msg, field); + constexpr_p, no_implicit_p, diag, field); } } @@ -1116,7 +1116,6 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, VEC(tree,gc) *vbases; int i, quals, flags; tsubst_flags_t complain; - const char *msg; bool ctor_p; if (spec_p) @@ -1240,25 +1239,21 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, quals = TYPE_UNQUALIFIED; argtype = NULL_TREE; - if (!diag) - msg = NULL; - else if (assign_p) - msg = ("base %qT does not have a move assignment operator or trivial " - "copy assignment operator"); - else - msg = ("base %qT does not have a move constructor or trivial " - "copy constructor"); - for (binfo = TYPE_BINFO (ctype), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) { tree basetype = BINFO_TYPE (base_binfo); + + if (!assign_p && BINFO_VIRTUAL_P (base_binfo)) + /* We'll handle virtual bases below. */ + continue; + if (copy_arg_p) argtype = build_stub_type (basetype, quals, move_p); rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - constexpr_p, no_implicit_p, msg, basetype); + constexpr_p, no_implicit_p, diag, basetype); if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) { /* In a constructor we also need to check the subobject @@ -1271,7 +1266,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, throw) or exception-specification (a throw from one of the dtors would be a double-fault). */ process_subob_fn (rval, false, NULL, NULL, - deleted_p, NULL, NULL, NULL, + deleted_p, NULL, NULL, false, basetype); } @@ -1288,21 +1283,31 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, } vbases = CLASSTYPE_VBASECLASSES (ctype); - if (vbases && assign_p && move_p) + if (vbases == NULL) + /* No virtual bases to worry about. */; + else if (assign_p && move_p && no_implicit_p) { + /* Don't implicitly declare a defaulted move assignment if a virtual + base has non-trivial move assignment, since moving the same base + more than once is dangerous. */ /* Should the spec be changed to allow vbases that only occur once? */ - if (diag) - error ("%qT has virtual bases, default move assignment operator " - "cannot be generated", ctype); - else if (deleted_p) - *deleted_p = true; + FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo) + { + tree basetype = BINFO_TYPE (base_binfo); + if (copy_arg_p) + argtype = build_stub_type (basetype, quals, move_p); + rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); + if (rval && rval != error_mark_node + && move_fn_p (rval) && !trivial_fn_p (rval)) + { + *no_implicit_p = true; + break; + } + } } else if (!assign_p) { - if (diag) - msg = ("virtual base %qT does not have a move constructor " - "or trivial copy constructor"); - if (vbases && constexpr_p) + if (constexpr_p) *constexpr_p = false; FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo) { @@ -1312,35 +1317,29 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - constexpr_p, no_implicit_p, msg, basetype); + constexpr_p, no_implicit_p, diag, basetype); if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) { rval = locate_fn_flags (base_binfo, complete_dtor_identifier, NULL_TREE, flags, complain); process_subob_fn (rval, false, NULL, NULL, - deleted_p, NULL, NULL, NULL, + deleted_p, NULL, NULL, false, basetype); } } } - if (!diag) - /* Leave msg null. */; - else if (assign_p) - msg = ("non-static data member %qD does not have a move " - "assignment operator or trivial copy assignment operator"); - else - msg = ("non-static data member %qD does not have a move " - "constructor or trivial copy constructor"); + + /* Now handle the non-static data members. */ walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals, copy_arg_p, move_p, assign_p, spec_p, trivial_p, deleted_p, constexpr_p, no_implicit_p, - msg, flags, complain); + diag, flags, complain); if (ctor_p) walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier, sfk_destructor, TYPE_UNQUALIFIED, false, false, false, NULL, NULL, deleted_p, NULL, - NULL, NULL, flags, complain); + NULL, false, flags, complain); pop_scope (scope); diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted37.C b/gcc/testsuite/g++.dg/cpp0x/defaulted37.C new file mode 100644 index 0000000..69105cc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted37.C @@ -0,0 +1,21 @@ +// DR 1402 +// { dg-do compile { target c++11 } } + +struct A +{ + int moved = 0; + A& operator=(A&&) { ++moved; } + ~A() { if (moved > 1) __builtin_abort(); } +}; + +struct B: virtual A { B& operator=(B&&) = default; }; +struct C: virtual A { }; // { dg-error "operator=.const A&" } + +int main() +{ + B b1, b2; + b2 = static_cast(b1); + + C c1, c2; + c2 = static_cast(c1); // { dg-error "operator=.const C&" } +}