Bug 14442 – Wrong this.outer reference in nested classes
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
Linux
Creation time
2015-04-13T08:02:00Z
Last change time
2016-02-01T17:14:23Z
Keywords
accepts-invalid, diagnostic
Assigned to
nobody
Creator
ibuclaw
Comments
Comment #0 by ibuclaw — 2015-04-13T08:02:26Z
This is an extension of runnable/nested.d:test35()
---
class Foo35
{
int x = 42;
void bar()
{
int y = 43;
new class Object
{
this()
{
//writefln("x = %s", x);
//writefln("y = %s", y);
assert(x == 42);
assert(y == 43);
assert(this.outer.__monitor is null); // <-- nested.d(14): Assertion failure
}
};
}
}
void test35()
{
Foo35 f = new Foo35();
f.bar();
}
---
The place in marked above will assert at runtime because it's value is '43'. This tells us that the frontend thinks that the parent chain of the inner class should be 'Foo35' and not the closure that 'Foo35.bar' creates.
What should happen is that a compiler error be issued.
nested.d(14): Error: no property '__monitor' for type 'void*'
Comment #1 by ibuclaw — 2015-04-13T08:10:44Z
Also affects the debug code written. As all you see of this parent chain is garbage values.
(gdb) p this
$1 = (__anonclass1 &) @0x7ffff7ed5fc0:
{
<Object> = {
__vptr = 0x4890e0 <vtable nested.Foo35.bar().__anonclass1>,
__monitor = 0x0
},
this = @0x7ffff7ed6ff0 // <-- closure pointer
}
(gdb) p this.this
$2 = (Foo35 &) @0x7ffff7ed6ff0:
{
<Object> = {
__vptr = 0x7ffff7ed5fe0, // <-- Foo35 object reference
__monitor = 0x2b // <-- 'y' value
},
x = 0 // <-- Excess garbage
}
Comment #2 by public — 2015-04-13T08:17:26Z
Is it effectively another manifestation of "have one context pointer, need many" issue?
Comment #3 by ibuclaw — 2015-04-13T09:32:59Z
(In reply to Dicebot from comment #2)
> Is it effectively another manifestation of "have one context pointer, need
> many" issue?
Maybe... though in this scenario you can get away with just the one context pointer:
anonclass this
{
void *this (bar.__closptr)
{
Foo35 this
{
int x = 42;
}
int y = 43;
}
}
So you know that the following:
assert(x == 42);
assert(y == 43);
Is lowered to:
assert((cast(Foo35)(*cast(CLOSURE bar *)this.this)).x == 42);
assert((cast(CLOSURE bar *)this.this).y == 43);