[gnu.g++.bug] user-defined conversion bug

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;
}