[comp.os.msdos.programmer] Borland International Responds to Turbo C++ bug list.

ericm@ims.UUCP (Eric Martinson) (11/21/90)

The following is a posted list of bugs found in Turbo C++.  The list
was uploaded to Borland via BIX (Byte Info eXchange).  Borland responded
to the list and reposted it on BIX.  I obtained acceptance from Borland
to repost it on News, include BI's comments.  There isn't a great deal
of information here.  The most interesting point is that BI actually
responded.  There may be a bug discussed here that you have run into.
The list was created, as shown below, by Marshal P. Cline, Ph.D.  I
don't want to take credit, all I did was send it to BI and get a response.
 
        Product:        Borland Turbo-C++ 1.0
 
        Author:         Marshall P. Cline, Ph.D.
                        ECE department
                        Clarkson University
                        Potsdam, NY  13676
 
        Voice:          315-268-3868
        Secretary:      315-268-6511
        FAX:            315-268-7600
 
        ARPA:           cline@sun.soe.clarkson.edu -or- bh0w@clutx.clarkson.edu
        Bitnet:         BH0W@CLUTX
        UUnet:          uunet!clutx.clarkson.edu!bh0w
 
        Copyright:      The Author releases this to the Public Domain
 
        Date:           June 11, 1990
        Revised:        August 9, 1990
        Revised:        August 14, 1990
 
 
Copyright:
    This file, along with code fragments it contains, is public domain.
    That means no one (including myself) can restrict its use/distribution.
    In particular, you can't copyright it.  No one can.  Not even me.
 
Contributions:
    If you have a TC++ bug to report, please email to the above addresses.
    But please try to find/send a work-around to the problem/bug.
    Also please explicitly state that your comments/code are public domain.

==========================
borland/long.messages #27, from lbenner, 9387 chars, Fri Nov  9 18:58:20 1990
--------------------------
TITLE: Borland's Comments to Emartinson's Bug List
Borland has added comments to the items listed in this file
originally posted as #25 from emartinson.
Lori Borland

-----------------------------------------------------------------

[1]
Several classlib\include\*.h have #include "foo.h" rather than
<foo.h>. This will only cause a problem if you have an 
indentically named header file in your current working directory 
(#include "file.h" starts in current dir, then searches the 
"standard places"; <file.h> only searches standard places). Note 
that TC++ by default doesn't find the classlib header files; if 
you want it to, add the line to turboc.cfg:  -IC:\TC\CLASSLIB\INCLUDE

BI comments:
   Not a "BUG".  Discussion of how include files work is correct 
   by ANSI C. The coding of the examples reflects the coding 
   style of the ple who generated them.  This could be changed, 
   but not a high ority issue.
=================================================================

[2]
Some include files have #ifndef __FILENAME_H, others have
#ifndef _FILENAME_H. (inconsistent #leading underscores).  See 
for example sortable.h vs set.h, etc.

BI comments:

   True this is inconsistent, but causes NO problems.  Perhaps
   it could be changed, but not high priority.
=================================================================

[3]
TCCNVT.EXE (the configuration file converter) isn't in the
distribution.

BI comments:
   TRUE.  Still not available.
=================================================================

[4]
`make -n' looks for and reads `builtins.mak' ONLY if it's in the
current dir. Naturally this is a bug, since make can't give an 
accurate picture of what a real `make' would do without the 
macros and implicit rules in `builtins.mak'.


BI comments:
    TRUE.  Fixed as of version 1.01.
=================================================================

[5]
<iostream.h> always includes <mem.h> which slows compilation
some.  In fact <iostream.h> doesn't need `NULL', and only needs 
memcpy() if _BIG_INLINE_ is defined, which will probably be 
rare.  Therefore the line

        #include <mem.h>        // to get memcpy and NULL

can be replaced with:

        #ifdef _BIG_INLINE_
        #include <mem.h>        // to get memcpy
        #endif

Since nearly everything includes <iostream.h>, and since
relatively few things will want _BIG_INLINE_, this should be a 
winner.  Note however that some code might assume <iostream.h> 
pulls in <mem.h>.

BI comments:
   iostream.h is big and slow to compile.  Other speedups are to
   remove all the comments from the file.  This speeds up 286 
   machines.
=================================================================

[6]
<iomanip.h> needs <iostream.h> but doesn't get it.  Add this to
<iomanip.h>:

        #ifndef __IOSTREAM_H
        #include <iostream.h>
        #endif

BI comments:
   TRUE.  Not in AT&T spec.  Not changed in current version.
   Probably should be.
=================================================================

[7]
There is no <new.h>.  I constructed the following work-alike. It 
should go into your standard include directory (where 
<iostream.h> is, for example):
        // new.h
        // Author: Dr. Marshall Cline/ECE Dept/Clarkson
	//	   Univ/Potsdam,NY 13676
        // Email: cline@sun.soe.clarkson.edu
        // Phone: Voice: 315-268-6511; Fax: 315-268-7600
        // Copyright: The Author releases this to the Public Domain, 9-July-90.
        // Date: 9-July-1990
        // Please include these acknowledgements when distributing this file
        #ifndef __NEW_H
        #define __NEW_H
        #ifndef _SIZE_T
        #define _SIZE_T
        typedef unsigned size_t;
        #endif
        void*  operator new(size_t size, void* ptr);
        // _new_handler is a ptr to a parameterless function returning void
        extern void (*_new_handler)();
        void (*set_new_handler(void (*replacement_handler)()))();
        #endif __NEW_H

BI comments:
   NEW.H is NOT defined by AT&T 2.0 C++ specs.  The contents
   were in C++ specs 1.2 and is making a comeback in the 
   upcoming ANSI C++ spec. We do have the underlying code, ie 
   _new_handler support, but it is not documented. It would be 
   nicer to use a typedef for the void function pointer, for the 
   above work-around.
=================================================================

[8]
Bug in istream: an extremely common C++ main input loop is
something like:
                while (cin >> chunk) chunk.do_something();

This works under the condition that istream::operator void*
returns 0 (false) after the input stream reads past EOF (or 
encounters an error). TC++'s iostream.h is consistent with its 
documentation [programmer's guide p.183] in stating that this 
operator returns 0 only when istream::fail() is true (when
failbit, badbit or hardfail are set), but unfortunately `fail'
doesn't get set after you've read past EOF.  The correct 
operation is to return 0 (false) on the read after you've run 
into EOF as well [Lippman p.384], which CAN BE accomplished by 
the _bad bit being set wnen seeking past end-of-file [Lippman
p.402].  This can be fixed by changing "ios::operator void*()"
in <iostream.h> as follows:

        inline _Cdecl ios::operator void* ()
        { return (state & (eofbit|failbit|badbit|hardfail)) ? 0 : this; }

NB: the `official' (if there is such a thing in these ANSI-C++ 
    pre-days) vior of istream::operator>> isn't clear.  I've 
    behadiscussed matter with Borland, and with a collegue who is 
    in bothcharge of certain libraries de AT&T, and no one is 
    yet sure insiwhat is really ``supposed'' appen. above patch 
    (checking the The eofbit) appears to work correctly, it may 
    hat a more be tcomprehensive solution is eventually in 
    order. ny event, mostpeople's code doesn't run around 
    checking individual bits de insian ios, he above is probably 
    `safe'.

BI comments:
   Although this code happens to work in AT&T's CFRONT
   implementation of C++, there is no documentation stating how 
   this code should operate. To test for EOF we recommend 
   breaking the statement down ie ifstream joe;
 
   while (!joe.eof())
   {
       joe >> ch;
   } 

   This should be up for debate by the C++ developers.
=================================================================

[9]

There is an error in TCC that isn't in TC (they generate
different code). [Borland is as surprised that they'd behave 
differently as I was; I'd imagine the internals are identical, 
and this assumption has be confirmed by Borland]. When a virtual 
fn is called from a non-virtual inline member, the virtualness
of the call vanishes.  Compile the following with `tcc -vi':

        #include <iostream.h>
        class B {
        public:
          virtual void virt();
          void nonvirt() { cout << "B::nonvirt() calling "; virt(); }
        };
        class D : public B {
        public:
          void virt();
        };

        main()
        {
          D d;
          (&d)->nonvirt();  // B::nonvirt() should call D::virt()
          d.nonvirt();      // ditto
        }
        void B::virt() { cout << "B::virt()\n"; }
        void D::virt() { cout << "D::virt()\n"; }

Unfortunately both of these call B::nonvirt(). Ie:Both 
d.nonvirt() & (&d)->nonvirt() translate to "call near ptr 
@B@virt$qv". Obviously these should be virtual function calls.  
This is a serious error, as calling a virtual from a non-virtual 
is fairly common.  Note: if B::virt() is a pure virtual (another 
legal operation, but perhaps not as common), the call to 
"@B@virt$qv" generates a linker error (there is no B::virt()!).  
If B::nonvirt() is a regular (non-inline) function (either by
moving it out of the class, or by `-v' or `-vi-'), TCC generates 
the correct code.  Strangely enough, TC appears to *always* 
generate the correct code.

BI comments:
   TRUE, and fixed as of version 1.01.
=================================================================

[10]
The 1.2 streams package (called <stream.h>) is nice, however
AT&T treats the inclusion of <stream.h> as an alias to 
<iostream.h>.  Therefore you should rename it from <stream.h> to 
<oldstream.h>, and let <stream.h> simply be:

                #include <iostream.h>

It is notable that a number of posters on comp.lang.c++ have
been confused by including <stream.h> thinking they were getting 
<iostream.h>...


BI comments:
   TRUE, but this is a 2.0 implementation and have included
   oldstreams as an added feature.
=================================================================

[11]
<generic.h>: Instead of using the usual "name2" style macros,
Borland invented their own set of macros for concatenating 
pieces of names.  Any code using the Stroustrup-style macros 
(eg. code compatable with g++, CC, or Zortech C++) will break.  
A work-around is to stick the following on the bottom of your 
<generic.h>:

                        #define name2 _Paste2
                        #define name3 _Paste3
                        #define name4 _Paste4

This bug and its work-around is thanks to:
        Pete Humphrey / pete@edsr.eds.com / 505-345-1863
        EDS Research / 5951 Jefferson Street NE / Albuquerque,
        NM  87109-3432

BI comments:
     TRUE.  As to why . . . copyright issues.
=================================================================

[12]
TC++ signals a compiler error when the LAST default parameter for 
a constructor is initialized by a constructor for some other 
class.  A workaround is to add an extra dummy default parameter 
of some predefined type like int.  Ex: if A and B are classes, 
then:

This will be an error:                A::A(B b = B(...));
But this is ok:                        A::A(B b = B(...), int dummy=0);

Thanks to:Zerksis Umrigar/umrigar@bingvaxu.cc.binghamton.edu/SUNY 
Binghamton NY

BI comments:
   Could not reproduce.

=================================================================
[13]
When an object is created as a side effect of an expression, and 
the expression is short-circuited, the destructor for the object 
seems to get called anyway:

        class X {
        public:
          X   create_copy_of_X() { return *this; }        //Return *BY VALUE*
          int whatever();
          //...
        };
        main()
        {
          X x;
          //...
          if (0 && x.create_copy_of_X().whatever()) stmt;
          //...
        }

At the close of main(), TC++ calls a destructor on the copy of 
`x' even though the copy was never properly constructed.  This 
only happens when inline functns are NOT inlined.  Thanks to: 
Jamshid Afshar/jamshid@ccwf.cc.utexas.edu

BI comments:
        True.  Fixed in v1.01
=================================================================

-- 
This is a test