D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 14442 - Wrong this.outer reference in nested classes
Summary: Wrong this.outer reference in nested classes
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All Linux
: P1 major
Assignee: No Owner
URL:
Keywords: accepts-invalid, diagnostic
Depends on:
Blocks:
 
Reported: 2015-04-13 08:02 UTC by Iain Buclaw
Modified: 2016-02-01 17:14 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Iain Buclaw 2015-04-13 08:02:26 UTC
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 Iain Buclaw 2015-04-13 08:10:44 UTC
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 Dicebot 2015-04-13 08:17:26 UTC
Is it effectively another manifestation of "have one context pointer, need many" issue?
Comment 3 Iain Buclaw 2015-04-13 09:32:59 UTC
(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);
Comment 4 Kenji Hara 2015-12-14 15:30:20 UTC
This would be a root of issue 15422. Will be fixed by:
https://github.com/D-Programming-Language/dmd/pull/5308
Comment 5 github-bugzilla 2016-02-01 17:14:20 UTC
Commit pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/8c60fe029f576efacc7bd15f6bec52d0d652c97c
fix Issue 14442 - Wrong this.outer reference in nested classes