[cxx-abi-dev] pointer-to-data-member representation for null pointer is not conforming

John McCall rjmccall at apple.com
Fri Dec 21 05:24:32 UTC 2012


On Dec 20, 2012, at 9:14 PM, Dennis Handly <dhandly at cup.hp.com> wrote:

>> From: Richard Smith <richardsmith at google.com>
>> struct E {};
>> struct X : E {};
>> struct C : E, X { char x; };
> 
>> char C::*c1 = &C::x;
>> char X::*x = (char(X::*))c1;
>> char C::*c2 = x2;
> 
> Should this just be "x"?
> 
>> [expr.static.cast]p12, we can convert a pointer to a member of a derived
>> class to a pointer to a member of a base class
> 
> Even if that class doesn't have members of that type?

Yes.  There's a note in [expr.static.cast]p12 that makes this pretty clear:

N3376 [expr.static.cast]p12:
  If class B contains the original member, or is a base or derived class of
  the class containing the original member, the resulting pointer to member
  points to the original member. Otherwise, the result of the cast is undefined.
  [Note: although class B need not contain the original member, the dynamic
  type of the object on which the pointer to member is dereferenced must
  contain the original member; see [expr.mptr.oper]. — end note]

It's one of the laundry list of things that completely dooms any type-specific
optimization of member pointers.

I would personally have preferred a completely different pointer-to-member
model where base classes have to be complete types and upcasts are
undefined unless the member is a member of the base class, but that is
not the language that the committee has seen fit to bless us with.

>> the conversion from x to c2 preserves the -1 value (conversion of
>> a null member pointer produces a null member pointer), giving the wrong
>> value for x2, and resulting in main returning 0, where the standard
>> requires it to return 1 (likewise, returning x != 0 would produce the wrong
>> value).
> 
> I assume that x and x2 are really the same, typo?
> 
> Trying this with g++ (4.2.1), I get the right answer.

I believe there are situations in which g++ doesn't appropriately check for null
before applying a non-trivial pointer-to-member conversion.  For example,
given Richard's setup,
  int X::*x = 0;
  int C::*c = x; // g++ just adds the offset, making this no longer a null member pointer

> Looking at the assembly, there doesn't seem to be any code to handle NULL
> being cast back to a derived class.

Yep.

John.


More information about the cxx-abi-dev mailing list