Bug 15684 - Pointer to member function called on incomplete type should diag
Summary: Pointer to member function called on incomplete type should diag
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.0
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid
: 18933 32416 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-05-27 16:36 UTC by gianni
Modified: 2021-07-16 07:55 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2005-06-19 15:01:46


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description gianni 2004-05-27 16:36:23 UTC
Leor Zolman posted this example on comp.lang.c++

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=due8b09cd2lp3kip4ivtcrn2m3nu6jvmuu%404ax.com

It seems according to the standard that the code below is illegal.  However it
is accepted by all compilers I know of.  I verified that 3.4.0 accepts the code
below.


#include <iostream>
using std::cout;
using std::endl;

class A;

class B {
    public:
        typedef void (A::*ftype)();
        void CallIt(A *ap, ftype f)
        {
            (ap->*f)(); // Is this legal with ptr to incomplete type A?
        }
};

class A
{
    public:
        void method_for_B() {
            std::cout << "In method_for_B...()" << std::endl;
        }

};

int main()
{
    void (A::*fp)() = &A::method_for_B;
    A a1;
    B b1;
    b1.CallIt(&a1, fp);
    return 0;
}
Comment 1 Andrew Pinski 2004-05-27 17:00:09 UTC
Not a bug.
From the standard, 8.3.3:
class Y;
char Y::* pmc; 
...
Similarly, the declaration of pmc is well-formed even though Y is an incomplete type. 
Comment 2 Leor Zolman 2004-05-27 17:12:01 UTC
(In reply to comment #1)
> Not a bug.
> From the standard, 8.3.3:
> class Y;
> char Y::* pmc; 
> ...
> Similarly, the declaration of pmc is well-formed even though Y is an 
incomplete type. 

OK, I'm no expert, but all it says is that the declaration is well-formed, not 
that you can actually use it (the way they show pmi and pmf being used)
   -leor

Comment 3 Andrew Pinski 2004-05-27 17:18:44 UTC
Why do you think it will not work, as the point-to-member function type is just have a reference to the 
offset at which you call the function nothing more (well there is more but that is an ABI definition).
Since the pointer-to-member type includes all the needed info there is no reason why it should not 
work.
Comment 4 gianni 2004-05-27 19:40:25 UTC
> Why do you think it will not work ...

I think it's not a question of wether it works or not, it's more an issue of
wether it is legal according to the standard.  In the c.l.c++ thread I cited
earlier, there is an assertion that a call can only be made when the class is
complete.

I personally like the gcc behaviour and if anything I'd like to see this caught
in strict mode only.  An alternative would be to write up a defect report on the
standard since it seems all the compilers are consistant !  I don't have my copy
of the standard handy to I can't say for sure.
Comment 5 Andrew Pinski 2004-05-27 19:49:06 UTC
I cannot find where in the C++ standard that this is invalid and in the thread it only says that they 
contracted EDG, if you think this is an issue, raise it to comp.lang.c++.moderated instead and then 
when they decide it is invalid you can reopen this bug.
Comment 6 Andrew Pinski 2004-05-27 19:52:17 UTC
Always this already came up in that newsgroup before: <http://groups.google.com/groups?
hl=en&lr=&ie=UTF-8&c2coff=1&threadm=3ACC2828.45CA0D3C%40dresdner-
bank.com&rnum=1&prev=/groups%3Fq%3Dincomplete%2Btypes%2Bpointer%2Bto%2Bmember%2Bgroup:
comp.lang.c%252B%252B.moderated%26hl%3Den%26lr%3D%26ie%3DUTF
-8%26group%3Dcomp.lang.c%252B%252B.moderated%26c2coff%3D1%26selm%3D3ACC2828.45CA0D3C
%2540dresdner-bank.com%26rnum%3D1>.
Comment 7 Leor Zolman 2004-05-27 20:29:26 UTC
(In reply to comment #5)
> I cannot find where in the C++ standard that this is invalid and in the 
thread it only says that they 
> contracted EDG, if you think this is an issue, raise it to 
comp.lang.c++.moderated instead and then 
> when they decide it is invalid you can reopen this bug.

The citation from the standard is (5.5p3):

3 The binary operator ->* binds its second operand, which  shall  be  of
   type  "pointer  to member of T" (where T is a completely-defined class
   type) to its first operand, which shall be of type "pointer to  T"  or
   "pointer  to  a class of which T is an unambiguous and accessible base
   class."  The result is an object or a function of the  type  specified
   by the second operand.

"where T is a completely-defined class type" is pretty cut-and-dried. Plus,
as John Spicer has indicated to me in a private email:

"An implementation could choose different forms of pointer-to-member 
representations depending on whether or not the class had virtual functions, or 
something like that.  In such implemenations, a complete type would be needed 
to get correct behavior."  
    -leor





Comment 8 Andrew Pinski 2004-05-27 20:32:56 UTC
Read the link I gave gives a different story in that it is always valid.
Comment 9 gianni 2004-05-27 20:48:57 UTC
About Leor's citation on virtual's being difficult.  It seems like it's not so
hard after all.  BTW I also tried this example where B::CallIt was in a
different translation unit and it all worked fine.  So, while I can agree that
you might need different implementation for pointer to virtual member function
and regular member functions, it seems like gcc at least has no such issue.
(tested on 3.4.0).

#include <iostream>
using std::cout;
using std::endl;

class A;

class B {
    public:
        typedef void (A::*ftype)();
        void CallIt(A *ap, ftype f)
        {
            (ap->*f)(); // Is this legal with ptr to incomplete type A?
        }
};

class A
{
    public:
        virtual void method_for_B() {
            std::cout << "A In method_for_B...()" << std::endl;
        }

};

class AX
  : public A
{
    public:
        virtual void method_for_B() {
            std::cout << "AX In method_for_B...()" << std::endl;
        }

};

int main()
{
    void (A::*fp)() = &A::method_for_B;
    AX a1;
    B b1;
    b1.CallIt(&a1, fp);
    return 0;
}

oh - here is the link again, hopefully without wrapping

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&c2coff=1&threadm=3ACC2828.45CA0D3C%40dresdner-bank.com&rnum=1&prev=/groups%3Fq%3Dg:thl1416673164d%26dq%3D%26hl%3Den%26lr%3D%26ie%3DUTF-8%26c2coff%3D1%26selm%3D3ACC2828.45CA0D3C%2540dresdner-bank.com
Comment 10 Leor Zolman 2004-05-27 21:46:18 UTC
> oh - here is the link again, hopefully without wrapping
> http://groups.google.com/groups?hl=en&lr=&ie=UTF-
8&c2coff=1&threadm=3ACC2828.45CA0D3C%40dresdner-bank.com&rnum=1&prev=/groups%
3Fq%3Dg:thl1416673164d%26dq%3D%26hl%3Den%26lr%3D%26ie%3DUTF-8%26c2coff%3D1%
26selm%3D3ACC2828.45CA0D3C%2540dresdner-bank.com

That worked. I'm confused by some things Kanze says in that article. First, 
there's this:

   The question was whether you can take a pointer to member function 
   on an incomplete class.  I don't think that the standard says
   anything about this directly.

But the way I read it, 5.5.3 is /very/ clear and direct. You can't do it.
Then there's this:

   More generally, the standard always specifies when an incomplete type 
   is illegal; using an incomplete type in a context which requires a
   complete type makes the program ill-formed, and requires a
   diagnostic.  Considering this, it is interesting that 5.5 makes no
   such restriction.  I interpret this to mean that you can also
   dereference the pointer without completing the type; the following
   is legal:

    class X ;

    void
    f( X* pc , void (X::*pmf)() )
    {
        (pc->*pmf)() ;
    }

Here again, the Standard says something must be a complete type (OK, the term 
actually used is "completely-defined", but I'm assuming that's the same thing), 
and Kanze is saying that the Standard "always specifies" when an incomplete 
type is illegal? As if saying something "must be completely-defined" is 
insufficient?

Kanze goes on to show the /exact/ situation we're talking about, but he seems 
to think the Standard sanctions it. Help me out here, I don't get it.
    -leor






Comment 11 Giovanni Bajo 2004-05-28 01:10:44 UTC
Given the quote from the standard, I think this is pretty clearly a bug
Comment 12 Andrew Pinski 2004-05-28 01:42:02 UTC
Confirmed, note that is well defined though as ->* is the pointer-to-member of T only T needs to be 
completely-defined and not the left side.
class A
{};
class B;
class C
{
        typedef void (A::*ftype)();
        C(B* a){a->*ftype();}
}
Comment 13 Andrew Pinski 2004-05-28 01:46:45 UTC
Woops my example is invalid too.
Comment 14 Andrew Pinski 2004-12-10 21:09:30 UTC
*** Bug 18933 has been marked as a duplicate of this bug. ***
Comment 15 Andrew Pinski 2004-12-10 21:41:40 UTC
Ok, now we produce an error_mark_node which seems wrong if we don't produce an error.
Comment 16 Andrew Pinski 2007-06-20 13:44:37 UTC
*** Bug 32416 has been marked as a duplicate of this bug. ***
Comment 17 Jonathan Wakely 2021-07-16 07:55:31 UTC
This is Core DR 1340 which was moved as a DR in 2012, making the standard match what all compilers already did.

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1340