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