Author: Aleksander Lodwich
          [EMAIL PROTECTED]

Referencing: Suse Linux gcc 3.3.1

Dear developers of GCC,

I write to you because we have experienced trouble with the newer variants of gcc.



----------
Problem 1:

----------
Wrong referencing


I'm not using the most recent version of gcc but I guess these problems haven't been addressed, yet, hence I don't expect them to be solved. Main point about these problems is that they must have come to GCC somewhere after the version 2.95.3 in which they don't occur. Many problems I'd like to present rely on the fact, that the current gcc version doesn't accept this:


class ClassA
{
public:
                ClassA( void );
};

...

void ClassB::Function( ClassA &Obj ) //Referenced operand
{
}


void ClassB::Function2( ClassA Obj ) //by value operand { }


//somewhere else in code...
{
...
ClassB B;
B.Function( ClassA() ); //doesn't compile because references cannot be obtained for temporary objects: ClassA( ClassA ) constructor not found!
B.Function2( ClassA() ); //works fine


//alternative:
        {
        ClassA A;
        B.Function( A ); //works fine with references
        }
...
}

Ok, why is this behaviour bad?
Whereas it's acceptable to work around this problem in the way proposed above, this still doesn't change the fact that it must be an error since
the two following lines have semantically exactly the same meaning.


B.Function( ClassA() );         =       {
                                        ClassA AnyName;
                                        B.Function( AnyName )
                                        };


This error has significant meaning for the usage of nested calls and operators. That's because the upper workaround solution cannot be
applied to all places where correct referencing is required.


let's assume:

class Matrix
{
public:
Matrix ( Matrix X ); //doesn't make sense and does not compile - would cause infinite loop
Matrix ( Matrix &X ); //ok, but often requires a const Matrix &X which again is not OK!
Matrix ( Matrix *X ); //ok
virtual Matrix ( void );



virtual Matrix operator* ( Matrix Operand1 ); //compiles virtual void operator= ( Matrix Operand2 ); //compiles };


I admit, this is not very fast, but that's not the point of. These are legal definitions that also make practical sense in real projects.
There are several strange things that happen then:


Case 1:
{
Matrix A, B, C;

//Here: B is set some values
//Here: C is set some values

A = B * C; //will not compile with gcc 3.3.1!! it didn't compile with gcc 3.1.x either.
}


Case 2:
{
Matrix A, B, C;

//Here B is set some values
//Here C is set some values

B * C; //will compile with gcc
}

Case 3 workaround:
{
Matrix A, B, C;

//Here B is set some values
//Here C is set some values

A = B; //will compile with gcc
A *= C; //will compile with gcc
}

This simple statement in case 1 will not compile. But why? Well, this statement suffers from the limitation discussed first.
The operator* returns as a result a temporary Matrix object, that obviously needs to be copied into the operator='s Operand2. Copying happens with the
Matrix( Matrix & ) constructor but the compiler looks for a Matrix( Matrix ) constructor that neither makes sense nor can be defined.


There's another problem with referencing in gcc.

let's assume:
Case 4:
void SomeFunction( Matrix B )
{
Matrix A;
Matrix C = B; //will not compile - Matrix( const Matrix & ) constructor not found!
Matrix C = B * A; //will not compile - Matrix( const Matrix & ) constructor not found!
}


One thing that upsets me here is that I explicitely use the = operator! This must be respected since its not always the same thing!!
As a programmer I expect gcc to make a


Matrix C;
C = B;

out of it. Otherwise I would say:

Case 5:
void SomeFunction(  Matrix B )
{
Matrix C( B ); //will compile
Matrix C( B * A ); //will not compile - Matrix( Matrix ) constructor not found
}


In case 4 the gcc compiler cries for a Matrix( const Matrix & ) constructor that no one has ever defined or asked for.
//This error message would be OK if SomeFunction()
//would take a const operand like this:
void SomeFunction( const Matrix B )
{
Matrix A;
//The following messages are OK because operator* and operator= weren't defined for const objects!
Matrix C = B; //will not compile - Matrix( const Matrix & ) constructor not found!
Matrix C = B * A; //will not compile - Matrix( const Matrix & ) constructor not found!
}



I guess since most programers work basically with pointers, obviously this problem didn't becomes apparent.
However the same examples I did show you do compile on the gcc 2.95.3 that I also have available. Therefore I think
that this compiler behaviour definitively IS an error.



Problem 2

----------
Wrong this pointer.

Well, another problem I've noticed occures when deriving from multiple base classes. The this pointer is only correct for the
main base class.


//The main base class
class Main
{
        Main( void )
        {
        this->Method(); //runs well because this* is OK!
        }

void    Method( void )
        {
        }
};


//one of many further base classes class Sub { Sub( void ) { this->Method(); //runtime error // this* is invalid!! }

void    Method( void )
        {
        }
};


//Combined class: class Together : public Main, public Sub { Together( void ); };

//in body:
Together::Together( void )
        :Main(), Sub()
{
}


//somewhere in Code: { Together *Obj = new Together(); //will crash

Main *M = dynamic_cast<Main *>( Obj ); //works fine
Sub *S = dynamic_cast<Sub *>( Obj ); //returns something obscure, not NULL and not the *Obj pointer
}



In project where multiple inheritance and dynamic casting is an issue, the this pointer problem can hook a team for quite a while.





---------- Problem 3Well, how to call it?

The last problem I'd like to mention here is again a problem of referencing:

let's assume:

//Matrix class:
Matrix Matrix::SomeFunction( void )
{
Matrix Dumb;
return Dumb;
}


//MatrixConsumer class: void MatrixConsumer::TakeMatrix( Matrix &Matrix ) { Matrix.Invert(); //or do whatever }


//somewhere in the code: { MatrixConsumer C; Matrix M; ...

C.TakeMatrix( M.SomeFunction() ); //doesn't compile
}

The third problem is about that in the case of functions the reference is looking up the pointer to the function instead of to the resulting object.
Typcial compiler messages look like that:
MatrixConsumer::TakeMatrix( Matrix::SomeFunction*& ) not found.



Finally.

----------
These problems have a significant impact on the quality of work with GCC. In our case these problems break tons of code that was working before the gcc upgrade. Fixing these problems is often difficult and very time consuming not talking about heavy changes to the look and feel of the code. In fact these compiler errors would be qualified as "show stoppers" as in fact they are in our case.



Sincerely, Aleksander Lodwich.

P.S. The world community is proud of their gcc developers. :)

__
[EMAIL PROTECTED]







Reply via email to