Re: Attention ROOT users: bug in GCC

Matthew D. Langston (langston@SLAC.stanford.edu)
Sat, 25 Oct 1997 16:51:24 -0700


Hello Pasha and Fons,

I'd like to reiterate that this is not a bug in gcc/g++. Please see
the original thread discussing this problem in the RootTalk Digest at
http://root.cern.ch/root/roottalk/0991.html.

Pasha originally reported that declaring a function as virtual in a
class definition resulted in the gcc/g++ compiler discarding the
definitions of methods defined inline within the class definition.
Below I have included a slightly simplified example that demonstrates
Pasha's original problem.

** begin test.cc example **
class A
{
public:

int f() { return 1; }
virtual int vg();
};

int
main()
{
A a;
int b = a.f();
}
** end test.cc example **

Pasha was concerned that he didn't see the definition of `A::f()' in
test.o when he compiled test.cc using the command `g++ -c test.cc':

langston@seto$ g++ -c test.cc
langston@seto$ nm -C test.o
0000002c W A::A(void)
U A virtual table
U A::f(void)
00000000 t gcc2_compiled.
00000000 T main

Pasha is certainly correct that `test.o' does not contain the assembly
code for `A::f()' (as evidenced in the output of `nm -C test.o' above by
the `U' to the left of the symbol `A::f(void)'). However, this is
because `test.o' *should not* contain the definition of *any* member
functions of `class A' (unless optimization is turned on - see
http://root.cern.ch/root/roottalk/0995.html for why this is so).

The reason that `test.o' does not contain the definition for `A::f()'
is because `class A' is an incomplete type since `A::vg()' is
undefined. Had `A::vg()' been defined in `test.cc' (go ahead and try
this yourself) then `class A' would have been completely defined and the
compiler would have emitted all of the assembly code concerning `class
A' into `test.o'.

This reason that g++ behaves in this way is a good thing, otherwise
some information will be duplicated in each object file that includes
the class definition of `class A' (backup copies of inline member
functions, compiler generated constructors, debugging information, the
internal tables that implement virtual functions, etc.).

This is a common problem for C++ compilers (not just g++). The method
that the GNU C developers chose to solve this problem was to emit the
definitions of inline member function in the same translation unit where
the classes vtable is emitted. According to the GNU C manual: "...if a
class has any non-inline virtual functions, the vtable will be emitted
in the translation unit containing the first one of those.".

Therefore, in our `test.cc' example, the definition of `A::f()' will
be emitted in the same translation unit where `A::vg()' is defined.
Since Pasha never defined the virtual member function is his original
example, the definition for `A::f()' was silently discarded.

In the "old" days of g++ (specifically the 2.6.x series), the GNU C
developers gave us the `interface' and `implementation' pragmas to help
us solve the problem of duplicating compiler generated class information
in multiple `.o' files (these pragmas are what Pasha referred to in his
response below). These pragmas aren't used that much anymore, and
certainly not in the common case as exemplified by our `test.cc' example
above. Although one *could* use the `#pragma interface/implementation'
method to solve this common problem, `pramgas' are generally considered
evil and not to be used unless absolutely necessary - at best, pragmas
are non-portable. Rather than duplicating that information here, I'll
refer the interested reader to the section `C++ Interface' in the GNU C
manual.

--
Matthew D. Langston
Stanford Linear Accelerator Center
langston@SLAC.Stanford.EDU
(650)926-3279

Pasha Murat wrote: > > Fons Rademakers writes: > > Hi Pasha, > > > > what is the status of this g++ bug? I use g++ all the time in > > -g and -O mode without problems. Does the bug persist when you > > remove the (redundant) inline keyword? I never use "inline" for > > implicit inline functions (maybe thereby avoiding this problem > > which shows only in that case). > > > > Cheers, Fons. > > > -------------------------------------------------------------------------------- > Hi Fons, > > It doesn't matter whether or not word "inline" is present - problem still > persists. Jarek Grebieszkow (a lot of thanks to him!) posted to ROOTTALK a > workaround. I just repeat what he said once again: if each include file > starts from > > #ifdef __GNUG_ > #pragma interface > #endif > > and each source file starts from > > #ifdef __GNUG_ > #pragma implementation > #endif > > GCC does not "forget" about the inlines in the presence of "virtual" declarations. > (ifdef jackets used here not to confuse other compilers, essential is the presence > of pragma's). This solved all my problems. It would also be very interesting to > figure out why this problem doesn't affect ROOT core distribution. > > Regards, Pasha