commit ecab56abfba28779061cb26932ecc613898d5f9d
Author: Jason Merrill <jason@redhat.com>
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.
@@ -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
@@ -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);
new file mode 100644
@@ -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<B&>(*this); }
+
+int main()
+{
+ B b1 (123);
+ B b2 (0);
+
+ A& ar = b1;
+ ar = b2;
+
+ return b1.i;
+}