[comp.lang.c++] Truly Amazing inline constructor bug.

mikem@otc.UUCP (02/18/87)

I don't know what's causing the bug. I'm just posting this because
the machinations are unusually contorted and make a good bedtime story.
Hopefully this might be of information to those who guide and fix cfront.
(How's tricks, Bjarne?)

In article <396@inria.UUCP>, shapiro@inria.UUCP (Marc Shapiro) writes:

> 3) I have a wierd problem with an inline constructor when the derived
> class has 2 constructors.  Below is the simplest example I have been
> able to devise which exposes the bug.  As you see the program passes
> CC but the code emitted for the 2nd constructor of the derived class
> is incorrect.  If I comment out either of the 2 lines marked "/* !!!! */",
> or if I use only one constructor in the derived class,
> then this code compiles correctly.  If you have a patch for this I
> would much appreciate.
> 
>     typedef	unsigned int	u_int;
> 
>     class base {
>      protected:
> 		  base();
>     };
> 
>     class derived: public base {
>      public:
> 		  derived(u_int dataSize);
> 		  derived(u_int offset,
> 			  u_int length);
>     };
> 
> 	inline				/* !!!! */
>      base::base () {
>      }
> 
>      derived::derived ( u_int dataSize) {
> 	  u_int size = dataSize;
> 	  base* mb
> 	      = new base()	               /* !!!! */
> 		  ;
>      }
> 
>      derived::derived (u_int offset,
> 		       u_int length) {
>      }
> 
> Compilation log:
> 
>     CC -I/users/shapiro -c tstmsg.c
>     CC  tstmsg.c:
>     cc  -c  tstmsg..c -lC
>     "tstmsg.c", line 5: redeclaration of _base__ctor
>     mv: tstmsg..o: Cannot access: No such file or directory

The first question is "Why have an inline constructor outside the class?"

I assume that the example is just a simplified one, and does actually
spring from a sensible real program. I found the following behaviour
in various cases which may amuse people with warped sense of humour:

------ FIRST EPISODE: ------------------------------------------------

The C-code generated is:

/* <<cfront 05/20/86>> */
/* < inline.c */

int    *_new();
int    _delete();
int    *_vec_new();
int    _vec_delete();

typedef unsigned int    u_int;

struct base { /* sizeof = 1 */
    char    _dummy; 
};

struct base *_base__ctor();

struct derived { /* sizeof = 1 */
    char    _dummy; 
};

/* overload _ctor: */
struct derived *_derived__ctorFUI__();
struct derived *_derived__ctorFUI_UI__();

struct derived *_derived__ctorFUI__(_auto_this, _auto_dataSize)
register struct derived *_auto_this;
u_int _auto_dataSize;
{
    u_int _auto_size;
    struct base *_auto_mb;

    struct base *_auto__Xthis__ctor_base;

    if (_auto_this == 0)
        _auto_this = (struct derived*)_new((long)1);

    _auto_this = (struct derived*)((((((struct base*)_auto_this)) == 0) ? (_new((long)1)) : 0), (((struct base*)_auto_this)));

    _auto_size = _auto_dataSize;
    _auto_mb = (struct base*)((_auto__Xthis__ctor_base = 0), ((_auto__Xthis__ctor_base = (struct base*)_new((long)1)), _auto__Xthis__ctor_base));

    return _auto_this;
};

static struct base *_base__ctor();   /* THIS CONFLICTS WITH THE EARLIER */
				     /* struct base *_base__ctor();     */

struct derived *_derived__ctorFUI_UI__(_auto_this, _auto_offset, _auto_length)
register struct derived *_auto_this;
u_int _auto_offset;
u_int _auto_length;
{ 
    if (_auto_this == 0)
        _auto_this = (struct derived*)_new((long)1);

    _auto_this = (struct derived*)_base__ctor(((struct base*)_auto_this));

				/* NOTE: base ctor isn't inline-substitued */

    return _auto_this;
};


/* AND HERE WE HAVE A NON_INLINE VERSION OF base's CTOR */

static struct base *_base__ctor(_auto_this)
register struct base *_auto_this;
{ 
    if (_auto_this == 0)
        _auto_this = (struct base*)_new((long)1);

    return _auto_this;
}


/* the end */

------ SECOND EPISODE: ------------------------------------------------

Removing the line

	base *mb = new base();

yields the C-code:


/* [... same initial stuff as above] */

struct derived *_derived__ctorFUI__(_auto_this, _auto_dataSize)
register struct derived *_auto_this;
u_int _auto_dataSize;
{
    u_int _auto_size;

    if (_auto_this == 0)
        _auto_this = (struct derived*)_new((long)1);

    _auto_this = (struct derived*)((((((struct base*)_auto_this)) == 0) ? (_new((long)1)) : 0), (((struct base*)_auto_this)));

    _auto_size = _auto_dataSize;

    return _auto_this;
};


struct derived *_derived__ctorFUI_UI__(_auto_this, _auto_offset, _auto_length)
register struct derived *_auto_this;

u_int _auto_offset;

u_int _auto_length;
{ 
    if (_auto_this == 0)
        _auto_this = (struct derived*)_new((long)1);

    _auto_this = (struct derived*)((((((struct base*)_auto_this)) == 0) ? (_new((long)1)) : 0), (((struct base*)_auto_this)));

			/* Now it IS inline-substituted ! */

    return _auto_this;
};

/* NOTE: no non-inline version of base ctor. */

/* the end */

------ THIRD EPISODE:  ------------------------------------------------------

The really amazing thing is that if you reverse the order in which
the two derived constructors occur in the file (i.e: derived(u_int) comes
after derived(u_int,u_int)) then you get:


/* [ ... same initial stuff as above ] */

struct derived *_derived__ctorFUI_UI__(_auto_this, _auto_offset, _auto_length)
register struct derived *_auto_this;

u_int _auto_offset;

u_int _auto_length;
{ 
    if (_auto_this == 0)
        _auto_this = (struct derived*)_new((long)1);

    _auto_this = (struct derived*)((((((struct base*)_auto_this)) == 0) ? (_new((long)1)) : 0), (((struct base*)_auto_this)));

			/* NOTE: base ctor has been inline-subsituted */

    return _auto_this;
};


struct derived *_derived__ctorFUI__(_auto_this, _auto_dataSize)
register struct derived *_auto_this;

u_int _auto_dataSize;
{
    u_int _auto_size;
    struct base *_auto_mb;

    struct base *_auto__Xthis__ctor_base;

    if (_auto_this == 0)
        _auto_this = (struct derived*)_new((long)1);

    _auto_this = (struct derived*)((((((struct base*)_auto_this)) == 0) ? (_new((long)1)) : 0), (((struct base*)_auto_this)));

    _auto_size = _auto_dataSize;
    _auto_mb = (struct base*)((_auto__Xthis__ctor_base = 0), ((_auto__Xthis__ctor_base = (struct base*)_new((long)1)), _auto__Xthis__ctor_base)) ;
    return _auto_this;
};


/* the end */

------ EPILOG --------------------------------------------------------------

It seems as if the handling of derived::derived(u_int,u_int) looks to see
whether the base ctor has already been used, and if it has, but is inline,
it makes a non-inline copy for itself ????  The other strange thing is
that we aren't getting warnings about ctor args not being used.

Beats the crap out of me...

			Mike Mowbray
			Systems Development
			Overseas Telecommunications Commission (Australia)

UUCP:   {seismo,mcvax}!otc.oz!mikem              ACSnet: mikem@otc.oz