[gnu.g++.bug] MI bugs -- c'tors, virt fns

tuck@jason.cs.unc.edu (Russ Tuck) (02/22/90)

The example below shows that g++ invokes constructors for multiply virtually
defined objects in the wrong order, and invokes some virtual functions on
these objects with bad values of "this".

The class structure below is
	       ,-> derived_A -.
	base -<                >-> derived_AB
	       `-> derived_B -'
with all derivations "public virtual".  Each class has a constructor,
and the print statements and c'tor argument values used make it possible 
to see where and in what order the c'tors are invoked.

The first problem is that derived classes are constructed before base classes.
(C'tors for derived_A and derived_B are called before c'tor for base, so
base data "shared" is not initialized.)

The base class declares and defines four virtual functions.  Each derived
class redefines one of these, and all four are invoked on a derived_AB
object.  The correct function is called in each case, but the functions
redefined in derived_A and derived_B are called with bad values of "this".
These functions are passes a "this" value which points to the derived_AB
object.  As a result, these functions get garbage when they access member
data of their own class.  This is the second problem.

Cfront 2.0 (both directly from AT&T, and from Sun) does not exhibit either
problem.

The session below is on a Sun-4/280 running SunOS 4.0.3 with 
g++ 1.36.4 (built on gcc 1.36.93) and Sun's version of AT&T cfront 2.0.

(The bug is a real problem for me, because I have no work-around and I'll
be in real trouble if I can't get the larger program that shows this bug 
working soon.  Cfront 2.0 has an unrelated bug that I understand less well
and have no work around for, so I'm currently without a usable C++ compiler.
Even if AT&T fixed cfront tomorrow, they wouldn't release it for months,
so GNU is my best hope.)


# Here's the example program.  (Not preprocessed, because only includes
# stdio.h.  If you need it preprocessed anyway, tell me and I'll send it.)
tuck@jason> cat virt.C
/* Russ Tuck, 2/21/90. */
/* Show g++ bug handling virtual functions with multiple virtual inheritance.*/
#include <stdio.h>

class base {
 private:  int base_val;
 protected: int shared;
 public:
  			virtual base*			b();
  class   derived_A;	virtual derived_A*		d_A();
  class   derived_B;	virtual derived_B*		d_B();
  class   derived_AB;	virtual derived_AB*		d_AB();
  base(int n=0);
};
base::base(int n)
{ base_val = n; shared=n; printf("base(%d) (this = %lx)\n", n, (long)this); }
base*       base::b()
{ printf("base::b() (v=%d) returning %lx\n",base_val,(long)this);return(this);}
derived_A*  base::d_A()
{ printf("base::d_A() returning NULL\n"); return(NULL); }
derived_B*  base::d_B()
{ printf("base::d_B() returning NULL\n"); return(NULL); }
derived_AB* base::d_AB()
{ printf("base::d_AB() returning NULL\n"); return(NULL); }


class derived_A : virtual public base {
 private:  int A_val;
 public:
  derived_A* d_A();
  derived_A(int n=1);
};
derived_A::derived_A(int n) : base(n-1)
{ A_val = n;
  printf("derived_A(%d) (shared=%d) (this = %lx)\n", n, shared, (long)this);
}
derived_A* derived_A::d_A()
{ printf("base::d_A() (Av=%d) returning %lx\n",A_val,(long)this);return(this);}


class derived_B : virtual public base {
 private:  int B_val;
 public:
  derived_B* d_B();
  derived_B(int n=2);
};
derived_B::derived_B(int n) : base(n-2)
{ B_val = n;
  printf("derived_B(%d) (shared=%d) (this = %lx)\n", n, shared, (long)this);
}
derived_B* derived_B::d_B()
{ printf("base::d_B() (Bv=%d) returning %lx\n",B_val,(long)this);return(this);}


class derived_AB :
  virtual public derived_A,
  virtual public derived_B
{
 private:  int AB_val;
 public:
  derived_AB* d_AB();
  derived_AB(int n=3);
};
derived_AB::derived_AB(int n) :
       base(n+5), derived_A(n+10), derived_B(n+15)
{ AB_val = n;
  printf("derived_AB(%d) (shared=%d) (this = %lx)\n", n, shared, (long)this);
}
derived_AB* derived_AB::d_AB()
{ printf("base::d_AB() (ABv=%d) returning %lx\n",AB_val, (long)this);
  return(this);
}

main()
{
  derived_AB* AB_ptr;
  AB_ptr = new derived_AB(5);

  /* Each should print the same ptr value printed by corresponding c'tor. */
  printf("AB_ptr = %lx\n",         (long)AB_ptr);
  printf("AB_ptr->b() = %lx\n",    (long)AB_ptr->b());
  printf("AB_ptr->d_A() = %lx\n",  (long)AB_ptr->d_A());
  printf("AB_ptr->d_B() = %lx\n",  (long)AB_ptr->d_B());
  printf("AB_ptr->d_AB() = %lx\n", (long)AB_ptr->d_AB());
}


# Compile and run with G++.
tuck@jason> g++ -v virt.C
g++ version 1.36.4 (based on GCC 1.36.93)
 /usr/softlab/contrib/lib/g++-1.36.4/sparc_sunos/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dsparc -Dsun -Dunix -D__sparc__ -D__sun__ -D__unix__ virt.C /usr/tmp/cca18882.cpp
GNU CPP version 1.36.93
 /usr/softlab/contrib/lib/g++-1.36.4/sparc_sunos/gcc-cc1plus /usr/tmp/cca18882.cpp -quiet -dumpbase virt.C -version -o /usr/tmp/cca18882.s
GNU C++ version 1.36.4 (based on GCC 1.36.93) (sparc) compiled by GNU C version 1.36.
default target switches: -mfpu -mepilogue
 as -o virt.o /usr/tmp/cca18882.s
 /usr/softlab/contrib/lib/g++-1.36.4/sparc_sunos/gcc-ld -e start -dc -dp /lib/crt0.o virt.o -lg++ /usr/softlab/contrib/lib/g++-1.36.4/sparc_sunos/gcc-gnulib -lc
tuck@jason> a.out
derived_A(15) (shared=0) (this = ebf0)
derived_B(20) (shared=0) (this = ec04)
base(10) (this = ebe4)
derived_AB(5) (shared=10) (this = ebd8)
AB_ptr = ebd8
base::b() (v=10) returning ebe4
AB_ptr->b() = ebe4
base::d_A() (Av=60400) returning ebd8
AB_ptr->d_A() = ebd8
base::d_B() (Bv=60400) returning ebd8
AB_ptr->d_B() = ebd8
base::d_AB() (ABv=5) returning ebd8
AB_ptr->d_AB() = ebd8


# Compile and run with cfront 2.0 for comparison.  Output is correct.
tuck@jason> CC -v virt.C
Sun C++ 2.0 FCS  -  10/20/89
/usr/CC/sun4//cpp -C -B -Dc_plusplus=1 -D__cplusplus=1  -I/usr/CC/sun4/incl  virt.C >./C++.18888/cpptmp
/usr/CC/sun4/cfront +L +fvirt.C  <./C++.18888/cpptmp >./C++.18888/virt.c
cc   -I/usr/CC/sun4/incl  virt.c  -L/usr/CC/sun4/ -lC
# static constructors/destructors
nm  a.out | /usr/CC/sun4/munch  > ./C++.18888/__ctdt18888.c
tuck@jason> a.out
base(10) (this = 4420)
derived_A(15) (shared=10) (this = 442c)
derived_B(20) (shared=10) (this = 4414)
derived_AB(5) (shared=10) (this = 4400)
AB_ptr = 4400
base::b() (v=10) returning 4420
AB_ptr->b() = 4420
base::d_A() (Av=15) returning 442c
AB_ptr->d_A() = 442c
base::d_B() (Bv=20) returning 4414
AB_ptr->d_B() = 4414
base::d_AB() (ABv=5) returning 4400
AB_ptr->d_AB() = 4400
tuck@jason> 

Russ Tuck		               tuck@cs.unc.edu
UNC Dept. of Computer Science          ...!mcnc!unc!tuck
CB 3175, Sitterson Hall
Chapel Hill, NC 27599-3175, USA        (919) 962-1755 or 962-1700