tuck@jason.cs.unc.edu (Russ Tuck) (12/08/89)
The example programs below define classes A and B. A has operator+, and B has a user-defined conversion to A. The issue is an expression which uses A's + on B's objects, via the B->A conversion. I posted almost the same program to comp.lang.c++ yesterday, because cfront 2.0 seemed to be in error. Jonathan Shopiro of AT&T confirmed via mail that there is a probable bug in cfront, and suggested a workaround which is probably also better programming practice. (The workaround is to have the conversion return an A (value) instead of an A& (reference).) Unfortunately, the workaround reveals a bug in g++ 1.36.1. Here are the details... g++ = GNU g++ 1.36.1 CC.new = AT&T cfront 2.0 piglet = Sun-3/60, SunOS 4.0.3 [Bug 1: conversion fails.] tuck@piglet> cat type2ae.C class A { public: A(); friend const A operator+ (const A& lsrc, const A& rsrc); }; class B { public: B(); operator const A(); }; main() { A a0; B b0, b1; a0 = b0 + b1; } tuck@piglet> g++ -v -c type2ae.C gcc version 1.36.1 (based on GCC 1.36) /usr/softlab/contrib/lib/m68k_sunos/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -Dmc68010 type2ae.C /usr/tmp/cca01090.cpp GNU CPP version 1.36 /usr/softlab/contrib/lib/m68k_sunos/gcc-cc1plus /usr/tmp/cca01090.cpp -quiet -dumpbase type2ae.C -version -o /usr/tmp/cca01090.s GNU C++ version 1.36.1 (based on GCC 1.36) (68k, MIT syntax) compiled by GNU C version 1.36. default target switches: type2ae.C: In function int main (): type2ae.C:18: default type conversion for type `B' failed tuck@piglet> CC.new -c type2ae.C CC type2ae.C: cc -c type2ae.c [Bug 2 (related): g++ gets fatal signal when stub fn defns are added.] tuck@piglet> cat type2af.C class A { public: A(); friend const A operator+ (const A& lsrc, const A& rsrc); }; class B { public: B(); operator const A(); }; extern "C" { #include <stdio.h> } A::A() { printf("A::A();\n"); } const A operator+(const A& lsrc, const A& rsrc) { printf("const A operator+(const A& lsrc, const A& rsrc)\n"); A ta; return(ta); } B::B() { printf("B::B();\n"); } B::operator const A() { printf("operator const A()\n"); A* pa = new A; return(*pa); } main() { A a0; B b0, b1; a0 = b0 + b1; } [diff to show nothing changed, just added defns] tuck@piglet> diff type2ae.C type2af.C diff type2ae.C type2af.C 12a13,40 > extern "C" { > #include <stdio.h> > } > > A::A() > { > printf("A::A();\n"); > } > > const A operator+(const A& lsrc, const A& rsrc) > { > printf("const A operator+(const A& lsrc, const A& rsrc)\n"); > A ta; > return(ta); > } > > B::B() > { > printf("B::B();\n"); > } > > B::operator const A() > { > printf("operator const A()\n"); > A* pa = new A; > return(*pa); > } > tuck@piglet> g++ -v -c type2af.C gcc version 1.36.1 (based on GCC 1.36) /usr/softlab/contrib/lib/m68k_sunos/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -Dmc68010 type2af.C /usr/tmp/cca01134.cpp GNU CPP version 1.36 /usr/softlab/contrib/lib/m68k_sunos/gcc-cc1plus /usr/tmp/cca01134.cpp -quiet -dumpbase type2af.C -version -o /usr/tmp/cca01134.s GNU C++ version 1.36.1 (based on GCC 1.36) (68k, MIT syntax) compiled by GNU C version 1.36. default target switches: type2af.C: In method B::operator const class A (): type2af.C:38: Segmentation violation g++: Program cc1plus got fatal signal 11. tuck@piglet> CC.new type2af.C CC type2af.C: "type2af.C", line 22: warning: lsrc not used "type2af.C", line 22: warning: rsrc not used cc -L/usr/local/lib/CC2.0 type2af.c -lC tuck@piglet> a.out A::A(); B::B(); B::B(); operator const A() A::A(); operator const A() A::A(); const A operator+(const A& lsrc, const A& rsrc) A::A(); [This is the similar program which shows the cfront error. g++ does fine.] [The only difference is that the conversion is to A& instead of A. ] tuck@piglet> diff type2af.C type2ag.C 10c10 < operator const A(); --- > operator const A&(); 34c34 < B::operator const A() --- > B::operator const A&() tuck@piglet> cat type2ag.C class A { public: A(); friend const A operator+ (const A& lsrc, const A& rsrc); }; class B { public: B(); operator const A&(); }; extern "C" { #include <stdio.h> } A::A() { printf("A::A();\n"); } const A operator+(const A& lsrc, const A& rsrc) { printf("const A operator+(const A& lsrc, const A& rsrc)\n"); A ta; return(ta); } B::B() { printf("B::B();\n"); } B::operator const A&() { printf("operator const A()\n"); A* pa = new A; return(*pa); } main() { A a0; B b0, b1; a0 = b0 + b1; } tuck@piglet> g++ -v type2ag.C -lg++ gcc version 1.36.1 (based on GCC 1.36) /usr/softlab/contrib/lib/m68k_sunos/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -Dmc68010 type2ag.C /usr/tmp/cca01166.cpp GNU CPP version 1.36 /usr/softlab/contrib/lib/m68k_sunos/gcc-cc1plus /usr/tmp/cca01166.cpp -quiet -dumpbase type2ag.C -version -o /usr/tmp/cca01166.s GNU C++ version 1.36.1 (based on GCC 1.36) (68k, MIT syntax) compiled by GNU C version 1.36. default target switches: /usr/softlab/contrib/lib/m68k_sunos/gcc-as -mc68010 -o type2ag.o /usr/tmp/cca01166.s /usr/softlab/contrib/lib/m68k_sunos/gcc-ld /lib/crt0.o type2ag.o -lg++ -lg++ /usr/softlab/contrib/lib/m68k_sunos/gcc-gnulib -lc tuck@piglet> a.out A::A(); B::B(); B::B(); operator const A() A::A(); operator const A() A::A(); const A operator+(const A& lsrc, const A& rsrc) A::A(); tuck@piglet> CC.new type2ag.C CC type2ag.C: "type2ag.C", line 22: warning: lsrc not used "type2ag.C", line 22: warning: rsrc not used "type2ag.C", line 46: error: ambiguous use of overloaded +: B and B 1 error [Now for completeness, here's the preprocessor output from the file that ] [causes the fatal signal. ] tuck@piglet> g++ -v -E type2af.C gcc version 1.36.1 (based on GCC 1.36) /usr/softlab/contrib/lib/m68k_sunos/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dmc68000 -Dsun -Dunix -D__mc68000__ -D__sun__ -D__unix__ -Dmc68010 type2af.C GNU CPP version 1.36 # 1 "type2af.C" class A { public: A(); friend const A operator+ (const A& lsrc, const A& rsrc); }; class B { public: B(); operator const A(); }; extern "C" { # 1 "/usr/softlab/contrib/include/g++-include/stdio.h" 1 #pragma once # 79 "/usr/softlab/contrib/include/g++-include/stdio.h" # 108 "/usr/softlab/contrib/include/g++-include/stdio.h" extern struct _iobuf { int _cnt; char* _ptr; char* _base; int _bufsiz; short _flag; char _file; } _iob[]; # 171 "/usr/softlab/contrib/include/g++-include/stdio.h" extern "C" { int _doprnt(const char*, void*, struct _iobuf *); int _doscan( struct _iobuf *, const char*, ...); int _filbuf( struct _iobuf *); int _flsbuf(unsigned, struct _iobuf *); int fclose( struct _iobuf *); struct _iobuf * fdopen(int, const char*); int fflush( struct _iobuf *); int fgetc( struct _iobuf *); char* fgets(char*, int, struct _iobuf *); struct _iobuf * fopen(const char*, const char*); int fprintf( struct _iobuf *, const char* ...); int fputc(int, struct _iobuf *); int fputs(const char*, struct _iobuf *); int fread(void*, int, int, struct _iobuf *); struct _iobuf * freopen(const char*, const char*, struct _iobuf *); int fscanf( struct _iobuf *, const char* ...); int fseek( struct _iobuf *, long, int); long ftell( struct _iobuf *); int fwrite(const void*, int, int, struct _iobuf *); char* gets(char*); int getw( struct _iobuf *); int pclose( struct _iobuf *); struct _iobuf * popen(const char*, const char*); int printf(const char* ...); void puts(const char*); int putw(int, struct _iobuf *); int rewind( struct _iobuf *); int scanf(const char* ...); void setbuf( struct _iobuf *, char*); void setbuffer( struct _iobuf *, char*, int); void setlinebuf( struct _iobuf *); void setvbuf( struct _iobuf *, char*, int, int); int sscanf(char*, const char* ...); struct _iobuf * tmpfile(); int ungetc(int, struct _iobuf *); int vfprintf( struct _iobuf *, const char*, ...); int vprintf(const char*, ... ); char* sprintf(char*, const char* ...); char* vsprintf(char*, const char*, ...); } # 14 "type2af.C" 2 } A::A() { printf("A::A();\n"); } const A operator+(const A& lsrc, const A& rsrc) { printf("const A operator+(const A& lsrc, const A& rsrc)\n"); A ta; return(ta); } B::B() { printf("B::B();\n"); } B::operator const A() { printf("operator const A()\n"); A* pa = new A; return(*pa); } main() { A a0; B b0, b1; a0 = b0 + b1; }