www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 20458] New: CRTP + pass alias to virtual member to mixin =

https://issues.dlang.org/show_bug.cgi?id=20458

          Issue ID: 20458
           Summary: CRTP + pass alias to virtual member to mixin = runtime
                    crash
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: destructionator gmail.com

Encountered this during my android/jni stuff. Easier to describe with code than
with words:

----

mixin template Impl(T, string name){
        alias a = __traits(getMember, T, name); // comment this and it works
        static void impl() {
                auto t = new T();
                __traits(getMember, t, name)();
        }
}

class A(CRTP) {
        static foreach(memberName; __traits(derivedMembers, CRTP))
                mixin Impl!(CRTP, memberName);
}

class Foo : A!Foo {
        void test() {
                import core.stdc.stdio;
                printf("Success\n");
        }
}

void main() {
        Foo.impl();
}

----


Compiles successfully. Running it leads to crash.

Make `class Foo` into `final class Foo` and it works.

Put `final` on `void test` instead and it works here, but adding more members
can result in the wrong method being called. Leads me to believe the virtual
function slot gets confused.


Comment that `alias a = ....` line in there and it works. So the fundamental
problem is related to the alias being present in the mixin template, even if
never used.

So the alias of the virtual derived member appearing in the base class.
However, I believe the use of the curiously-recurring template pattern is
necessary to trigger the bug though since I've been unable to reproduce the
crash without that.


This is the most I have been able to minimize it... the original version is:


---
mixin template Impl(T, alias a) {
        static void impl() {
                auto t = new T();
                __traits(getMember, t, __traits(identifier, a))();
        }
}

class A(CRTP) {
        static foreach(memberName; __traits(derivedMembers, CRTP))
                mixin Impl!(CRTP, __traits(getMember, CRTP, memberName));
}

class Foo : A!Foo {
        void test() {
                import core.stdc.stdio;
                printf("Success\n");
        }
}

void main() {
        Foo.impl();
}
---

And I think it is worth noting that one too: just *passing* the alias to the
mixin template also results in the same behavior. It doesn't have to explicitly
mixin the alias, as long as it is present there.

--
Dec 19 2019