Re: Attention ROOT users: bug in GCC

From: Pasha Murat (murat@cdfsga.fnal.gov)
Date: Sun Oct 26 1997 - 03:05:07 MET


	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



This archive was generated by hypermail 2b29 : Tue Jan 04 2000 - 00:26:21 MET