This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Re: Internal compiler error 191
- To: Piotr dot Nestorow at telelogic dot se
- Subject: Re: Internal compiler error 191
- From: "Martin v. Loewis" <martin at loewis dot home dot cs dot tu-berlin dot de>
- Date: Sun, 19 Mar 2000 11:19:26 +0100
- CC: gcc-bugs at gcc dot gnu dot org
- References: <200003170919.KAA06036@blue.telelogic.com>
> 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