http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50282

--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> 2011-09-04 
18:45:24 UTC ---
The problem is is your code, not gcc

The type of &T4::f is void(T2::*)() not void(T4::*)() so when you cast the
pointer to void(T4::*)() you are not casting back to the original type.

You can fix the code by using reinterpret_cast<void(T2::*)()> for the cases
that use the expression &T4::f, instead of reinterpret_cast<void(T4::*)()>

For what it's worth, clang gives exactly the same result as g++ for a reduced
version of your program:

// define class N with no member,
// we just need a type void(N::*)() of which an object can hold a
pointer-to-member-function
class N {} ;

// define class T1 & T3 with some member data/functions
// so that an object of class T4 which derives from T1 & T2 & T3 
// will has its base object of type T2 have different address from the object
itself.
class T1
{
public:
  char c ;
  int i ; 
} ;

class T3:virtual public T1
{
public:
  int i3 ;
public:
  virtual void f2() {
    __builtin_printf("Foo3 !! this=%p\n", (void*)this);
  } ;
} ;

// define class T2 
// T2 has a memmber function f, which our pointer-to-member-function will point
to.
// as T4 derives from T2 as a public base type, this function is an accessable
from T4 ;
// the function outputs the value of 'this' pointer, which i expect it always
points to an object of T2.
class T2
{
public:
  int i2 ;
public:
  virtual void f() {
    __builtin_printf("Foo2 !! this=%p\n", (void*)this);
  } ;
} ;

// define class T4, which simply derives from T1&T2&T3
class T4:public virtual T1, public T3, public T2
{} ;



int main(int, char**)
{
  T4 t4 ;
  void (N::*pfn)() = 0;
  void(T4::*pf4)() = &T4::f ;

  // this line shows the address of t4 and its base object t4.t2 differ ;
  __builtin_printf("AddressOf t4=%p, t4.t2=%p\n", (void*)(&t4),
(void*)(&(T2&)(t4)));

  {
    __builtin_printf("\nwhat i expect:\n");
    // the following lines show what i expect to see:
    // no matter what form the function call is, the function tells me the
address of t4.t2
    t4.f() ;
    (t4.*(&T4::f))() ;
    (t4.*pf4)() ;
  }

  {    
    __builtin_printf("\nTestCase1:\n");
    __builtin_printf("pfn assignment: pfn =
reinterpret_cast<void(N::*)()>(&T4::f) \n");
    __builtin_printf("Function call form: (t4.*reinterpret_cast<void(T4::*)()>(
pfn )() \n");
    // Case1: 
    // pfn is assigned directly from &T4::f, 
    // but actually, its value shows that is &T2::f
    pfn= reinterpret_cast<void(N::*)()>(&T4::f) ;

    // comparing with the result i memtioned above, this is not what i want.
    (t4.*reinterpret_cast<void(T4::*)()>(pfn))() ;
  }

  {
    __builtin_printf("\nTestCase2:\n");
    __builtin_printf( "pfn assignment: pfn =
reinterpret_cast<void(N::*)()>(pf4) \n");
    __builtin_printf("Function call form: (t4.*reinterpret_cast<void(T4::*)()>(
pfn )() \n");
    // Case2: pfn is transfromed from pf4, which is defined as type
void(T4::*)(), and its value
    // has been correctly assigned as &T4::f, not &T2::f
    pfn = reinterpret_cast<void(N::*)()>(pf4) ;

    // this time, the function call works correctly
    (t4.*reinterpret_cast<void(T4::*)()>(pfn))() ;
  }

  {
    __builtin_printf("\nTestCase3:\n");
    // Case3:
    // this case exactly follows the standered draft, if anyone might say
    // in the above casese i used a lvalue(pfn), 
    // this time, i have rvalue only, but it's obviously not functioning.
    __builtin_printf("Function call form: (t4.*reinterpret_cast<void(T4::*)()>(
reinterpret_cast<void(N::*)()>(&T4::f)))() \n");
    (t4.*reinterpret_cast<void(T4::*)()>(
                                         reinterpret_cast<void(N::*)()>(&T4::f)
                                        ))() ;
  }
}


When the 1st and 3rd tests are altered to use reinterpret_cast<void(T2::*)()>
it gives the results you expect

so I think this is invalid

Reply via email to