From patchwork Tue Jun 15 20:06:45 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 55790 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 1D9AC1007D3 for ; Wed, 16 Jun 2010 06:07:01 +1000 (EST) Received: (qmail 6937 invoked by alias); 15 Jun 2010 20:07:00 -0000 Received: (qmail 6927 invoked by uid 22791); 15 Jun 2010 20:06:59 -0000 X-SWARE-Spam-Status: No, hits=-5.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_SF, 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; Tue, 15 Jun 2010 20:06:52 +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.13.8/8.13.8) with ESMTP id o5FK6kt3013739 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 15 Jun 2010 16:06:47 -0400 Received: from [IPv6:::1] (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o5FK6kWr023635 for ; Tue, 15 Jun 2010 16:06:46 -0400 Message-ID: <4C17DD55.9090407@redhat.com> Date: Tue, 15 Jun 2010 16:06:45 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.10) Gecko/20100603 Lightning/1.0b1 Shredder/3.0.6pre MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH to fix virtual overriding of operator= 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 Although a copy-assignment operator doesn't override a virtual copy-assignment operator from a base class, it can override a virtual assignment operator that takes a reference to the derived class. Tested x86_64-pc-linux-gnu, applying to trunk. commit ecab56abfba28779061cb26932ecc613898d5f9d Author: Jason Merrill Date: Tue Jun 15 12:26:57 2010 -0400 * class.c (add_implicitly_declared_members): Implicit assignment operators can also be virtual overriders. * method.c (lazily_declare_fn): Likewise. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 340fe87..60908ff 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2618,47 +2618,13 @@ add_implicitly_declared_members (tree t, { /* In general, we create destructors lazily. */ CLASSTYPE_LAZY_DESTRUCTOR (t) = 1; - /* However, if the implicit destructor is non-trivial - destructor, we sometimes have to create it at this point. */ - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)) - { - bool lazy_p = true; - - if (TYPE_FOR_JAVA (t)) - /* If this a Java class, any non-trivial destructor is - invalid, even if compiler-generated. Therefore, if the - destructor is non-trivial we create it now. */ - lazy_p = false; - else - { - tree binfo; - tree base_binfo; - int ix; - - /* If the implicit destructor will be virtual, then we must - generate it now because (unfortunately) we do not - generate virtual tables lazily. */ - binfo = TYPE_BINFO (t); - for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++) - { - tree base_type; - tree dtor; - - base_type = BINFO_TYPE (base_binfo); - dtor = CLASSTYPE_DESTRUCTORS (base_type); - if (dtor && DECL_VIRTUAL_P (dtor)) - { - lazy_p = false; - break; - } - } - } - /* If we can't get away with being lazy, generate the destructor - now. */ - if (!lazy_p) - lazily_declare_fn (sfk_destructor, t); - } + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) + && TYPE_FOR_JAVA (t)) + /* But if this is a Java class, any non-trivial destructor is + invalid, even if compiler-generated. Therefore, if the + destructor is non-trivial we create it now. */ + lazily_declare_fn (sfk_destructor, t); } /* [class.ctor] @@ -2697,6 +2663,34 @@ add_implicitly_declared_members (tree t, TYPE_HAS_CONST_ASSIGN_REF (t) = !cant_have_const_assignment; CLASSTYPE_LAZY_ASSIGNMENT_OP (t) = 1; } + + /* We can't be lazy about declaring functions that might override + a virtual function from a base class. */ + if (TYPE_POLYMORPHIC_P (t) + && (CLASSTYPE_LAZY_ASSIGNMENT_OP (t) + || CLASSTYPE_LAZY_DESTRUCTOR (t))) + { + tree binfo = TYPE_BINFO (t); + tree base_binfo; + int ix; + tree opname = ansi_assopname (NOP_EXPR); + for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ++ix) + { + tree bv; + for (bv = BINFO_VIRTUALS (base_binfo); bv; bv = TREE_CHAIN (bv)) + { + tree fn = BV_FN (bv); + if (DECL_NAME (fn) == opname) + { + if (CLASSTYPE_LAZY_ASSIGNMENT_OP (t)) + lazily_declare_fn (sfk_assignment_operator, t); + } + else if (DECL_DESTRUCTOR_P (fn) + && CLASSTYPE_LAZY_DESTRUCTOR (t)) + lazily_declare_fn (sfk_destructor, t); + } + } + } } /* Subroutine of finish_struct_1. Recursively count the number of fields diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 124a83c..97f3566 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1108,7 +1108,8 @@ lazily_declare_fn (special_function_kind sfk, tree type) /* Declare the function. */ fn = implicitly_declare_fn (sfk, type, const_p); /* A destructor may be virtual. */ - if (sfk == sfk_destructor) + if (sfk == sfk_destructor + || sfk == sfk_assignment_operator) check_for_override (fn, type); /* Add it to CLASSTYPE_METHOD_VEC. */ add_method (type, fn, NULL_TREE); diff --git a/gcc/testsuite/g++.dg/inherit/virtual5.C b/gcc/testsuite/g++.dg/inherit/virtual5.C new file mode 100644 index 0000000..bed0ef3 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/virtual5.C @@ -0,0 +1,29 @@ +// Test that a synthesized op= can override one from a base. +// { dg-do run } + +struct B; + +struct A +{ + virtual B& operator=(const B&); +}; + +struct B: A +{ + B(int i): i(i) { } + int i; + // implicitly-declared op= +}; + +B& A::operator=(const B& b) { return static_cast(*this); } + +int main() +{ + B b1 (123); + B b2 (0); + + A& ar = b1; + ar = b2; + + return b1.i; +}