On 08/08/2016 10:30 AM, Cauterite wrote:
See: https://dpaste.dzfl.pl/2ec6780d4b25
That code is short enough to post it here directly. For easier
reference, this is it:
struct S {
void f1() {
auto x = &this;
};
static void f2() {
static assert(!__traits(compiles, {auto x = &this;}));
};
};
static assert(is(typeof(S.f1) == typeof(S.f2))); // ?
static assert(is(typeof(&S.f1) == typeof(&S.f2))); // ?
static assert(!__traits(isStaticFunction, S.f1));
static assert(__traits(isStaticFunction, S.f2));
void main() {
// call f2;
S.init.f2();
// mov [ebp-4], S.init;
// lea eax, [ebp-4];
// call f1;
S.init.f1();
};
(Aside: no semicolons after function/struct declarations in D.)
We have two methods defined, f1 and f2, where f2 is static but they have
otherwise identical signatures.
We can see from the disassembly that f1 receives a `this` pointer while
f2 does not.
Yet, typeof(&f1) == typeof(&f2). This makes no sense, how can the
compiler even know whether to pass a `this` pointer when both methods
have same type?
The first assert compares the return types of f1 and f2. They both
return `void`, so everything's fine there.
The second assert is a bit more surprising. `&S.f1` is considered a
function, but `&S.init.f1` is a delegate. Obviously, you can't get a
proper delegate from just the type. You need an instance of the struct
for that. So having `&S.f1` be a delegate would be weird, too.
I don't know why `&S.f1` is allowed at all. Maybe there is a good
reason, but it also allows bad stuff like this:
struct S
{
void f1(int x) { import std.stdio; writeln(x); }
}
void main()
{
void function(int x) f = &S.f1;
f(42); /* prints garbage */
}
This even works in @safe code. It also works when using .funcptr to get
the function pointer from a delegate. I'v filed an issue:
https://issues.dlang.org/show_bug.cgi?id=16365