Re: Attention ROOT users: bug in GCC

Pasha Murat (murat@cdfsga.fnal.gov)
Sun, 26 Oct 1997 02:05:07 GMT


Hi Matthew,

I appreciate you returned back to this issue and shed a new light on it.
You are right: when A::vg() is defined in your example, GCC does everything
correctly.

What I call "bug" is that gcc *does not* complain about missing A::vg().
It just says that (in your example) "A virtual table" is missing...
You may certainly disagree with calling this a "bug", but in any case we
have here an example of the diagnostics which is rather misleading.
Let's take an example from "the life of non-advanced ROOTer": if you
accidentally missed ClassImp() macro in some place you end up with having
linker complaining about that a bunch of functions you've defined as inlines
are missing... And *no single word* about that one which actually caused the
diagnostics. It is very difficult for me to agree with you in that this is
a good thing...

Anyway, your explanation is pretty clear and the rest is mostly a matter of
terminology.

There is another GCC-related problem however, which might be pretty well
IRIX6.2 specific. I also can't exclude that it might have even more
limited scope (for example, it might be a local problem at Fermilab).
I return to it in hope that you could comment on it as well.

It seems that on IRIX 6.2 GCC (we have v2.7.2.1 installed on R10000 platform)
*doesn't do* inlining at all. If I compile your example with -O3 which
supposedly should turn ON all the optimizations including inlining, I still
get the following:

/cdf/upgrade/tracking/murat/g3/test>gcc -c -O3 $r1/testa.cc ; nm testa.o | grep f
U f__1A

Presence of undefined reference points out to that compiler didn't inline
A::f().

On AIX 4.2 however (where i installed GCC 2.7.2.2 myself) with -O3 turned ON
unresolved reference is not generated, so I guess that (at least some kind)
of inlining took place.

Thanks once again, Pasha.
--------------------------------------------------------------------------------
Matthew D. Langston writes:
> 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