[comp.lang.c++] Bugs in release 1.1

mikem@otc.OZ (Michael Mowbray) (11/19/86)

The following is a list of the bugs I noticed in release 1.1 of the C++
translator. If anyone has noticed other bugs please let me know. (If
info like this has already been posted, please forgive me. We've only
just started getting this newsgroup into Australia, so I don't know
what's gone before.)

Before I list the bugs, though, I ought to say that I've been using both
release 1.0 and 1.1 seriously for some time now and that the list below
should under no circumstances be taken the wrong way. Many of the bugs
are non-critical, although it's obviously desirable to fix them. (Is there
anyone out there besides Bell Labs who've fixed things in the translator
source code?)

*******************************************************************************
- Varargs problems. - The current code in the source module error.c has to
  be re-written to run on certain machines (read Pyramids). This isn't
  really a bug in the usual sense of the word and Bjarne tells me that
  he's redesigned error.c. The only reason I'm mentioning this here is that
  if you have a Pyramid, but couldn't make C++ run, let me know and
  I'll send you the diff's.

*******************************************************************************
 - Misleading Error Handling during parsing of class definition

        class Test {
                int i;
            public:
                Test(int ii = XXX);
                int showi() { return i; }
        };

gives the error message:

        line 6: error:  class Test is undefined

when it should recognize at line 4 that XXX is undefined. This is usually
only a bad problem when your class is big. If you get the message check
first that any default arguments that are macros have actually been defined
earlier.

*******************************************************************************
 - Problems with recognition of function types 

There are some problems when the translator is dealing with pointers to
functions with unknown arguments. The problems are summarised in the 
following program:

    //---------------------------------------------------------------
    typedef void Vfn(...);
    //---------------------------------------------------------------
        // Both the following should be of type Vfn.

    void f1()
    {
       int dummy=1;
    }

    void f2(int i)
    {
        int dummy = i;
    }
    //---------------------------------------------------------------
    main()
    {
        Vfn* vfp;

        vfp = f1; // okay.

        vfp = f2;  // gives "bad assignment type" error.
                   // The translator seems to be interpreting the type
                   // void Vfn(...) as void Vfn(), i.e: not remembering
                   // that any arguments are okay.
    }
    //---------------------------------------------------------------

*******************************************************************************
 - Taking address of non-lvalue


(Can be quite serious.)

    //---------------------------------------------------------
    class Crap {
            int i;
        public:
            Crap(int j) { i=j; }
            Crap operator+(Crap);
            int  operator==(Crap&);
    };

    Crap const nullcrap(0);

    Crap  Crap::operator+(Crap c)
    {
        return  Crap(i + c.i);
    }

    int  Crap::operator==(Crap& c)
    {
        return  i == c.i;
    }
    //---------------------------------------------------------
    main()
    {
        int    k;
        Crap   result(-1), c1(1), c2(2);

        if ((result = c1+c2) == nullcrap)  // This line generates wrong code.
            k = 1;
    }
    //---------------------------------------------------------


This generates the following C-code (which I've cb'd and edited to make more
readable). The error is at the line following " /*XXXXX*/ " :


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

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

  struct Crap { /* sizeof = 4 */
      int    _Crap_i;
  };

  struct Crap _Crap__plus();
  int         _Crap__eq();

  struct Crap nullcrap;

  struct Crap _Crap__plus(_auto_this, _auto_c)
  register struct Crap *_auto_this;
  struct Crap _auto_c;
  {
      struct Crap _auto__V1;

      return ((((((struct Crap*)(&_auto__V1))->_Crap_i = (_auto_this->_Crap_i + _auto_c ._Crap_i)), ((struct Crap*)(&_auto__V1)))), _auto__V1);
  }
 

  int    _Crap__eq(_auto_this, _auto_c)
  register struct Crap *_auto_this;
  struct Crap *_auto_c;
  {
      return (_auto_this->_Crap_i == (*_auto_c)._Crap_i);
  }


  int    main()
  { 
      _main();
       {
          int         _auto_k;
          struct Crap _auto_result;
          struct Crap _auto_c1;
          struct Crap _auto_c2;

          (((((struct Crap*)(&_auto_result))->_Crap_i = -1), ((struct Crap*)(&_auto_result))));

          (((((struct Crap*)(&_auto_c1))->_Crap_i = 1), ((struct Crap*)(&_auto_c1))));

          (((((struct Crap*)(&_auto_c2))->_Crap_i = 2), ((struct Crap*)(&_auto_c2))));

/*XXXXX*/
            /* In the following line " &(_auto_result = ....) " is ILLEGAL. */
 
          if (_Crap__eq(&(_auto_result = _Crap__plus(&_auto_c1, _auto_c2)), (struct Crap*)(&nullcrap)))
              _auto_k = 1;


            /* It should generate something like:               */
            /*   ...((_auto_result = ....), &_auto_result)...   */
      }
  };


  extern int    _STItst1_c_()
  { 
      (((((struct Crap*)(&nullcrap))->_Crap_i = ((int)0)), ((struct Crap*)(&nullcrap))));
  };

  /* the end */

*******************************************************************************
** BUG No6 - code generation fault **
*******************************************************************************

In the following case the C-code generation goes ga-ga:

        typedef void Vfn();
        typedef Vfn  *VfnP;

        void func()
        {
            // do nothing.
        }

        Vfn* returnVfn()        // screws this up
        {
            return func;
        }

        VfnP returnVfnP()       // but this is okay
        {
            return func();
        }


The C-Code generated is:

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

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

        typedef int    Vfn();
        typedef int    (*VfnP)();

        int    func()
        { 
        };


        int    (*returnVfn()    /* NICKERS IN A TWIST */
        {
            return (int(*)())(func);  }

        )();

        VfnP returnVfnP()       /* okay */
        {
            return (int(*)())(func);
        };

        /* the end */

*******************************************************************************
 - Visibility problem with protected members.

In release 1.1, the new language feature of protected members has been
surprisingly useful for me. (More so than I would have anticipated.)
One bug I've found is that friends of a derived class can't access
inherited protected members. E.g:

	class Base {
	    protected:
		int somemember;
	    public:
		Base(int i) { somemember=i; }
	};

	class Derived : public Base {
		friend class OtherClass;
	};

	class OtherClass {
        	int i;
	    public:
        	void set_i(Derived& d) { i = d.somemember; }
	};

  - This gives the error message:

		line 15: error:  somemember is protected

*******************************************************************************


			Mike Mowbray
			Senior Engineer
			Systems Development
			Overseas Telecommunications Commission (Australia)

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