D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 4860 - Taking delegates to a member function broken if method is also aliased in from a base class
Summary: Taking delegates to a member function broken if method is also aliased in fro...
Status: RESOLVED DUPLICATE of issue 3559
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 critical
Assignee: No Owner
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2010-09-13 07:53 UTC by David Nadlinger
Modified: 2012-02-11 21:01 UTC (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description David Nadlinger 2010-09-13 07:53:08 UTC
Consider the following example (the alias directive in there might seem strange, but is needed if there would be another, non-overridden overload of foo (see http://www.digitalmars.com/d/2.0/function.html#function-inheritance):

---
import std.stdio;

class Base {
  void foo() {
  }
}

class Derived : Base {
  alias Base.foo foo;
  override void foo() {
  }
}

void main() {
  auto d = new Derived();
  void delegate() dg = &d.foo;
  writefln("dg: (%s, %s)", dg.ptr, dg.funcptr);
}
---

As long as the alias is present, the delegate created via »&d.foo« is invalid – its funcptr part is null (and indeed, trying to call the delegate yields an access violation). If the alias directive is removed, everything works as expected, but as explained above, this is not an option.

What may be also relevant is that DMD fails to infer the type for »&d.foo« – replacing »void delegate() dg« with »auto dg« produces »cannot infer type from overloaded function symbol &d.foo«.

I would also be happy to learn about any workarounds, since this blocks the release of my D SWIG module.
Comment 1 David Nadlinger 2010-09-13 14:23:03 UTC
Iain pointed out on #d that the example above works if you put the alias directive *after* the last overload:

---
import std.stdio;

class Base {
  void foo() {
  }
}

class Derived : Base {
  override void foo() {
  }
  alias Base.foo foo;
}

void main() {
  auto d = new Derived();
  void delegate() dg = &d.foo;
  writefln("dg: (%s, %s)", dg.ptr, dg.funcptr);
}
---
Comment 2 Steven Schveighoffer 2010-09-13 14:31:07 UTC
In order to make this bug report valid, you should cite a better example.  In your example, you are overriding the base function, and then also aliasing it.  Yes, in the case you reference, it's valid, but your trivial example is nonsensical -- you get nothing by aliasing Base.foo in this case.

I am pretty sure you have a better example :)
Comment 3 David Nadlinger 2010-09-13 14:37:15 UTC
Steven, I am not quite sure if I see why a non-minimal code snippet in a bug report would be useful, but here you go:

---
import std.stdio;

class Base {
  void foo( int i ) {}
  void foo( string s ) {}
}

class Derived : Base {
  alias Base.foo foo;
  override void foo( int i ) {}
}

void main() {
  auto d = new Derived();
  void delegate( int ) dg = &d.foo;
  writefln("dg: (%s, %s)", dg.ptr, dg.funcptr);
}
---

Feel free to reduce that to the above test case again. ;)
Comment 4 Steven Schveighoffer 2010-09-13 14:46:31 UTC
(In reply to comment #3)
> Steven, I am not quite sure if I see why a non-minimal code snippet in a bug
> report would be useful

Because it avoids an argument against fixing the bug because the use case is completely useless.  Your new example is perfect, thanks!
Comment 5 nfxjfg 2010-09-13 19:07:55 UTC
What? A bug is a bug, it doesn't matter if the code causing it is nonsensical. A code snippet reproducing a bug should be as minimal as possible.
Comment 6 Don 2010-09-15 12:44:27 UTC
Wrong-code bugs are always important.
Here's a mitigation patch to turn it into a rejects-valid bug.
Haven't tracked down the root cause yet, but there certainly should be an assert in this function -- if it's a virtual function, it should have a non-negative vtable index, not -1.

e2ir.c, line 3275.  DelegateExp::toElem()

    Symbol *sfunc;
    int directcall = 0;

    printf("DelegateExp::toElem() '%s'\n", toChars());
+    if (func->isVirtual() && func->vtblIndex < 0)
+        error("Internal compiler error: malformed delegate. See Bugzilla 4860");
    sfunc = func->toSymbol();
    if (func->isNested())
Comment 7 Don 2010-11-19 22:16:42 UTC
That patch was a bit too early in the function. Should be e2ir.c, line 3308.
Still in DelegateExp::toElem().

        {
            // Get pointer to function out of virtual table
            unsigned vindex;

            assert(ethis);
            ep = el_same(&ethis);
            ep = el_una(OPind, TYnptr, ep);
            vindex = func->vtblIndex;
+    if (vindex < 0)
+        error("Internal compiler error: malformed delegate. See Bugzilla
4860");

            // Build *(ep + vindex * 4)
            ep = el_bin(OPadd,TYnptr,ep,el_long(TYsize_t, vindex * 4));
            ep = el_una(OPind,TYnptr,ep);
        }
Comment 8 Walter Bright 2010-12-27 18:00:27 UTC
Don's mitigation patch:

http://www.dsource.org/projects/dmd/changeset/824
Comment 9 Don 2010-12-27 22:04:25 UTC
Downgrading to rejects-valid, now that the patch is in place.
Comment 10 yebblies 2012-02-11 21:01:05 UTC
This is a symptom of issue 3359 - overload sets are not searched properly in some cases.

*** This issue has been marked as a duplicate of issue 3359 ***
Comment 11 yebblies 2012-02-11 21:01:49 UTC
This is a symptom of issue 3559 - overload sets are not searched properly in some cases.

*** This issue has been marked as a duplicate of issue 3559 ***