Abramo Bagnara wrote:
It's deliberate. I saw no reason to give it a distinct type. A
MemberPointerType to FunctionProtoType is a pointer to member function.
The only place where a member function can appear without a pointer to
it is in call expressions. You can't do anything with the function in
these cases except call it, so the type system gets along just fine.
The bug here is that the validation code for & takes a wrong path and
returns a normal PointerType to FunctionProtoType.
To tell you the truth, I'm a bit perplexed: I think that a non static
method type is something very different from an ordinary function type
and that they should not share the same type.
But they do! Look at this snippet; GCC accepts it:
typedef void FuncType();
FuncType func; // Declare a normal function called func, no return value
or parameters.
void func() { // Define func.
}
struct A {
FuncType mfunc; // Declare a member function called mfunc, no return
value or parameters.
};
void A::mfunc() { // Define mfunc.
}
If we use the same type, comparison of canonical type of a non static
method and canonical type of an ordinary function could wrongly succeeds
and I expect other problems following this path.
There is no way in valid C++ to create a situation where this is
relevant. If we have some bugs in this area, it's because we're not
intercepting invalid code early enough, as your two code examples show.
Also under a C++ standard perspective I don't see how a non static
method could be considered to have the same type of ordinary function,
they don't have neither the same arguments (because implicit "this"
argument).
What the standard says is only a minor consideration in the design of
Clang's data structures. More important is that using FunctionProtoType
directly simplifies a lot of code. Also, the implicit this doesn't
matter - take a look at the one important place where it could: the
standard explicitly says that it is ignored. I'm talking about overload
resolution, of course.
struct B {
static void fn(int);
void fn(double);
};
void test() {
B b;
b.fn(1); // Calls fn(int), ignoring the object argument
b.fn(1.0); // Calls fn(double), ignoring the object argument
}
The following C++ source (wrongly compiled by clang) is another small
snippet that shows the problems of current approach:
template <typename T>
void p(T, T);
void g();
struct c {
void h();
void f() {
__typeof(h) i;
return p(i, g);
}
};
But again, this is (or in the case of Clang, should be) rejected far
earlier, namely at __typeof(h). GCC complains that the type of the
member function is unknown. In other words, you're not allowed to apply
typeof to a member function. I'll have to check what C++0x says about
decltype, but I suspect it's the same thing.
Sebastian