pointers to member functions with multiple inheritance

Martin v. Loewis martin@loewis.home.cs.tu-berlin.de
Sun Jan 9 03:51:00 GMT 2000


> In one of those thoughts that strikes me right before I fall asleep, I
> realized that what is probably happening is a bug related to the virtual
> inheritance of the class that defines the member function I'm getting a
> pointer to.  This was verified when I commented out the virtual inheritance
> and the code ran perfectly.

This is indeed the problem. To encode a pointer to a virtual member,
g++ stores in the pointer the offset to the virtual method table, as
well as an index into the virtual method table.

To implement virtual bases, g++ adds an implicit member (the vbase
pointer) to the derived class. To get to the virtual table of the
virtual base, you'd have to first access the vbase pointer, and then
navigate to the virtual table from there. 

With the current compiler, this does not work. It wants to put an
absolute offset from the start-of-object to the vtable into the
object. Because you cannot give an absolute offset of a vbase, g++
internally sets that offset to 0. The code generating
pointer-to-member constants does not know about this, and emits the
zero as a real offset. At run-time, it accesses the first bytes as if
they were a vtable; that crashes pretty soon.

I don't see how this can be implemented for all cases, given the
current object layout. There are two bytes left in the
pointer-to-member format, which could be used to encode an offset to
the vbase pointer. There are two problems with that approach: What if
the vbase pointer is at offset 0, and what if you have to go through
multiple levels of vbase pointers?

To summarize, it seems that your code is not implementable without
changing the processing of virtual bases entirely. I'll check whether
the new ABI will be capable of supporting this case. For now, I
propose the patch below: The compiler rejects the code (as an
implementation limitation), instead of silently generating bad code.

Regards,
Martin

2000-01-09  Martin v. Löwis  <loewis@informatik.hu-berlin.de>

	* typeck.c (expand_ptrmemfunc_cst): Be sorry about pointers to
	virtual members of virtual bases.

// Build don't link:
class MultiBase
{
public:
  virtual int &getX(void) =0;
};

class Multi : virtual public MultiBase
{
public:
  Multi(int);
  int x;

  int &getX(void) { return x; }
};

Multi::Multi(int i):x(i){}		

int& (Multi::*ptr)() = &Multi::getX; // gets bogus error - sorry, vmember of vbase, XFAIL *-*-*
int main(void)
{
  Multi m(5);
  if ((m.*ptr)() != 5) 
    return 1;
}

Index: typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/typeck.c,v
retrieving revision 1.234
diff -u -r1.234 typeck.c
--- typeck.c	2000/01/05 10:10:53	1.234
+++ typeck.c	2000/01/09 11:43:42
@@ -6295,6 +6295,13 @@
          fn; the call will do the opposite adjustment.  */
       tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
       tree binfo = binfo_or_else (orig_class, fn_class);
+
+      /* If the function comes from a virtual base class, our
+	 pointer-to-member format does not support invoking the member
+	 from a derived class. Be sorry for now.  */
+      if (TREE_VIA_VIRTUAL (binfo))
+	sorry ("pointers to virtual members of virtual base classes");
+
       *delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
 
       /* Map everything down one to make room for the null PMF.  */


More information about the Gcc-patches mailing list