jj@idris.id.dk (Jesper Joergensen [ris]) (12/09/89)
Hi again, I'm sorry if this bug report seems a bit large, but don't worry!! I've thoroughly isolated the BUGs as best as I can and included some SIMPLE explanatory examples, which takes up some space, but should otherwise be quite clear and save you some troubles and tests. Hope it helps ... Contents: 1: Description of a bug that gives a function peculiar visibility outside the module in which it is declared. Source and assembler output for two examples are included. 2: Description of a bug concerning the use of 'operator=' in derived classes. Source and execution output included for two examples. Please notify me when you have received this letter, so that I can cancel them from my 'pending bug reports' list. We've been having some trouble with the local networks lately, so I would like to know if I can reach you (and the rest of the world) at all. I hope this isn't too much inconvenience. All examples are run with the '-v' compiler option so that you can see what happens and identify the compiler and environment. The only specialty is that my '/usr/local/lib/gcc-as' is a link to '/usr/local/bin/gas' so I'm using the GNU assembler (version 1.34, though I don't believe the assembler is 'guilty' in this case, but now you know). 1: Function visibility ====================== Below is a sample session collected by GNU emacs in shell mode, with source and assembler output included by 'cat'. Here we go: *** SAMPLE SESSION 1a START *** % pwd /usr/users/jj/GNUmail/g++errs % cat testlink.cc class Some { int member ; public: int change(int) ; } ; int Some::change(int nember) { int tember = member ; member = nember ; return tember ; } class Some_other { int member ; public: const int change(int nember) ; } ; int Some_other::change(int nember) { int tember = member ; member = nember ; return tember ; } class Some_other_again { int member ; public: const int change(int nember) ; } ; const int Some_other_again::change(int nember) { int tember = member ; member = nember ; return tember ; } % g++ -v testlink.cc -O -S gcc version 1.36.1 (based on GCC 1.36) /usr/local/lib/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dvax -Dunix -D__vax__ -D__unix__ -D__OPTIMIZE__ testlink.cc /usr/tmp/cc007031.cpp GNU CPP version 1.36 /usr/local/lib/gcc-cc1plus /usr/tmp/cc007031.cpp -quiet -dumpbase testlink.cc -O -version -o testlink.s GNU C++ version 1.36.1 (based on GCC 1.36) (vax) compiled by GNU C version 1.36. default target switches: -munix % cat testlink.s #NO_APP gcc_compiled.: .text .align 1 .globl _change__4Somei _change__4Somei: .word 0x0 movl 4(ap),r1 movl (r1),r0 movl 8(ap),(r1) ret .align 1 .globl _change__10Some_otheri _change__10Some_otheri: .word 0x0 movl 4(ap),r1 movl (r1),r0 movl 8(ap),(r1) ret .align 1 _change__16Some_other_againi: .word 0x0 movl 4(ap),r1 movl (r1),r0 movl 8(ap),(r1) ret **** SAMPLE SESSION 1a END **** Don't worry about the functionality of the assembler code, it's perfectly OK !!! The primary problem is that the third version of the 'change' function (in class Some_other_again) doesn't get a '.globl' statement for its name in the assembler output. The only difference between this and the preceeding (in class Some_other) is that the DEFinition of the function includes 'const'. The secondary problem is that the compiler doesn't complain about the difference between the DECLaration (within the class) and DEFinition (outside the class) of the second version of 'change' for the class 'Some_other'. The DECLaration includes 'const', while the DEFinition doesn't, but the compiler seems to forget this. NOTE: I've included this problem here because I think it might be correlated to the primary one, it was just a hunch I got. I've checked the ChangeLog for version 1.36.1 which says: *** QUOTE BEGIN *** Mon Nov 6 00:51:43 1989 Michael Tiemann (tiemann at arkesden) : Some other stuff deleted. : * cplus-decl2.c (grok_method_quals): New function. Incorporate `const' and `volatile' qualifiers into FUNCTION_DECLs and TYPE_DECLs. Uses code broken out of `grokclassfn'. * cplus-decl2.c (grokclassfn): Caller changed. * cplus-decl.c (grokdeclarator): Call `grok_method_quals' when QUALS is non-zero in declarator grokking loop. **** QUOTE END **** is it possible that this change is causing the error, so that a 'const' is interpreted as an 'extern' DECLaration ????????????? Below is an example causing exactly the same problem, but without the use of classes and members: *** SAMPLE SESSION 1b START *** % pwd /usr/users/jj/GNUmail/g++errs % cat testfunc.cc int change1(int nember) { return nember ; } const int change2(int nember) { return nember ; } % g++ -v testfunc.cc -O -S gcc version 1.36.1 (based on GCC 1.36) /usr/local/lib/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dvax -Dunix -D__vax__ -D__unix__ -D__OPTIMIZE__ testfunc.cc /usr/tmp/cc007056.cpp GNU CPP version 1.36 /usr/local/lib/gcc-cc1plus /usr/tmp/cc007056.cpp -quiet -dumpbase testfunc.cc -O -version -o testfunc.s GNU C++ version 1.36.1 (based on GCC 1.36) (vax) compiled by GNU C version 1.36. default target switches: -munix % cat testfunc.s #NO_APP gcc_compiled.: .text .align 1 .globl _change1__Fi _change1__Fi: .word 0x0 movl 4(ap),r0 ret .align 1 _change2__Fi: .word 0x0 movl 4(ap),r0 ret **** SAMPLE SESSION 1b END **** 2: Bug in derived class' use of assignment ========================================== Below is a sample program which illustrates the missing import of the assignment member function 'operator=' from the base to the derived class. The base class assignment operator changes the sign of the data member as a side effect, so that its invocation can be detected. *** SAMPLE SESSION 2a START *** % pwd /usr/users/jj/GNUmail/g++errs % cat testbase.cc extern "C" void printf (char *, ...) ; class Base { int member ; public: Base(const Base& x) { member = x.member ; } Base(int x) { member = x ; } void print_member() { printf ("member == %d\n", member) ; } const Base operator=(const Base& x) { member = - x.member ; return *this ; } } ; class Dpub : public Base { public: Dpub(int x) : (x) { } } ; int main() { Base b(23) ; Dpub dpub(23) ; b.print_member() ; dpub.print_member() ; b = b ; dpub = dpub ; b.print_member() ; dpub.print_member() ; return 0 ; } % g++ -v testbase.cc -O -o testbase gcc version 1.36.1 (based on GCC 1.36) /usr/local/lib/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dvax -Dunix -D__vax__ -D__unix__ -D__OPTIMIZE__ testbase.cc /usr/tmp/cc007100.cpp GNU CPP version 1.36 /usr/local/lib/gcc-cc1plus /usr/tmp/cc007100.cpp -quiet -dumpbase testbase.cc -O -version -o /usr/tmp/cc007100.s GNU C++ version 1.36.1 (based on GCC 1.36) (vax) compiled by GNU C version 1.36. default target switches: -munix /usr/local/lib/gcc-as -o testbase.o /usr/tmp/cc007100.s /usr/local/lib/gcc-ld -o testbase /lib/crt0.o testbase.o -lg++ /usr/local/lib/gcc-gnulib -lc % testbase member == 23 member == 23 member == -23 member == 23 **** SAMPLE SESSION 2a END **** Notice that the base class of the derived is 'public', so there is a conversion from the derived objects 'dpub' to the base class argument of 'Base::operator=', and the latter is a public member of the base class and should therefore be imported by the derived. As you can see from the output it obviously doesn't; bitwise copy is used instead. Now follows another example, where the derived class has a data member of its own, carefully observe what happens: *** SAMPLE SESSION 2b START *** % pwd /usr/users/jj/GNUmail/g++errs % cat testbase2.cc extern "C" void printf (char *, ...) ; class Base { int member ; public: Base(const Base& x) { member = x.member ; } Base(int x) { member = x ; } void print_member() { printf ("member == %d\n", member) ; } const Base operator=(const Base& x) { member = - x.member ; return *this ; } } ; class Dpub : public Base { int member2 ; public: Dpub(int x, int y) : (x) { member2 = y ; } void print_member() { Base::print_member() ; printf ("member2 == %d\n", member2) ; } } ; int main() { Base b(23) ; Dpub dpub(23,24) ; b.print_member() ; dpub.print_member() ; b = b ; dpub = dpub ; b.print_member() ; dpub.print_member() ; return 0 ; } % g++ -v testbase2.cc -O -o testbase2 gcc version 1.36.1 (based on GCC 1.36) /usr/local/lib/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dvax -Dunix -D__vax__ -D__unix__ -D__OPTIMIZE__ testbase2.cc /usr/tmp/cc007123.cpp GNU CPP version 1.36 /usr/local/lib/gcc-cc1plus /usr/tmp/cc007123.cpp -quiet -dumpbase testbase2.cc -O -version -o /usr/tmp/cc007123.s GNU C++ version 1.36.1 (based on GCC 1.36) (vax) compiled by GNU C version 1.36. default target switches: -munix /usr/local/lib/gcc-as -o testbase2.o /usr/tmp/cc007123.s /usr/local/lib/gcc-ld -o testbase2 /lib/crt0.o testbase2.o -lg++ /usr/local/lib/gcc-gnulib -lc % testbase2 member == 23 member == 23 member2 == 24 member == -23 member == -23 member2 == 24 **** SAMPLE PROGRAM 2b END **** Now the assignment operator IS used for the base part of the derived object. The reason for this very peculiar behavior is totally beyond my wildest imaginations, I haven't got the faintest idea of what might be causing this. Sorry, but I can't isolate the bug further. That's all i had to say this time. Thanks for your attention and an otherwise very useful compiler. I hope you'll respond as soon as possible so that I know when you've received this bug report. So long ... Jesper Jorgensen (known as 'JJ the famous') Research associate Department of Computer Science Technical University of Denmark DK-2800 Lyngby DENMARK