Patchwork C++ PATCH to fix virtual overriding of operator=

login
register
mail settings
Submitter Jason Merrill
Date June 15, 2010, 8:06 p.m.
Message ID <4C17DD55.9090407@redhat.com>
Download mbox | patch
Permalink /patch/55790/
State New
Headers show

Comments

Jason Merrill - June 15, 2010, 8:06 p.m.
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.

Patch

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.

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<B&>(*this); }
+
+int main()
+{
+  B b1 (123);
+  B b2 (0);
+
+  A& ar = b1;
+  ar = b2;
+
+  return b1.i;
+}