This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Internal compiler error 191


> We have found a problem in g++ (2.8.1 and 2.95.2) with
> the following expression:
> 
>    &((type *) 0)->member
> 
> where `type' is a class with multiple inheritance from two
> classes that have the same base class and `member' is inherited
> from the base class.

Thanks for your bug report. The compiler should not crash, that's why
I've put it into GNATS.

However, I think your program is has undefined behaviour, it
dereferences the null pointer. 5.2.5, [expr.ref]/3 says

# If E1 has the type "pointer to class X," then the expression E1­>E2
# is converted to the equivalent form (*(E1)).E2; the remainder of
# 5.2.5 will address only the first option (dot)

So your code is equivalent to 

    &(*(type*)0).member

Interesting enough, the standard never says that derefencing the null
pointer has undefined behaviour, it only says that it says :-)

Since it is undefined behaviour, the compiler can do what it pleases:
generate wrong code, or outright reject your code.

> We've used successfully the above trick in C to get the relative
> address of a struct member at compile time.

Please note that (AFAIK) this is already undefined in C. Instead, you
should use the offsetof macro to determine the offset of a field.

In C++, the offsetof macro is also available, but can be applied only
to a POD type, i.e. a plain old C structure. With inheritance, this
macro does not work, anymore.

> We think that in both cases the expression should be possible to
> evaluate correctly by the compiler to the relative offset of the
> class member.

No, that is not possible in the case of virtual bases. g++ currently
implements virtual bases using 'vbase pointers'. I.e. an object of
type B1 has the layout

[b1:4 byte][pointer-to-A:4 byte][a:4 byte]

You would think that a is at offset 8 of a B1*, right? Now look at the
layout of a C object

[b1][pointer-to-A][b2][pointer-to-a][c][a]

Now, if you have a C*, convert that to a B1*, and look at offset 8,
you'll find the beginning of a B2 object; the A object would be at
offset 16.

In general, you can find the offset of a member in a virtual base only
at run-time. In this case, you need a real object, which was allocated
in a constructor - otherwise, the vbase pointers won't be set-up
correctly. They are definitely incorrect for the null pointer.

Instead, I would recommend the same as g++ does: use
pointers-to-member to process field offsets.

Regards,
Martin


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]