Jump to page: 1 2 3
Thread overview
extern(C++) multiple inheritence
Jan 19, 2016
Manu
Jan 19, 2016
Daniel Murphy
Jan 19, 2016
Walter Bright
Jan 19, 2016
Daniel Murphy
Jan 20, 2016
Walter Bright
Jan 22, 2016
IgorStepanov
Jan 19, 2016
Manu
Jan 19, 2016
deadalnix
Jan 22, 2016
Walter Bright
Jan 23, 2016
Manu
Jan 24, 2016
Walter Bright
Jan 26, 2016
Manu
Jan 26, 2016
Walter Bright
Jan 26, 2016
Manu
Jan 26, 2016
Manu
Jan 26, 2016
Manu
Jan 26, 2016
Daniel Murphy
Jan 26, 2016
Manu
Jan 27, 2016
Manu
Jan 27, 2016
Manu
Jan 27, 2016
Walter Bright
Jan 28, 2016
Walter Bright
Jan 28, 2016
Manu
Jan 28, 2016
Walter Bright
Jan 28, 2016
Manu
Jan 28, 2016
Walter Bright
Jan 26, 2016
Manu
January 19, 2016
I'm repeating this here from the depths of my prior whinge thread, since this is kind of a new topic.

D's multiple inheritance solution is single-inheritance + interfaces. Rightly so, it's a great solution, and this matches what all the C++ programmers I've ever worked with do anyway. Trouble is, it doesn't seem to work with extern(C++) at the moment.

Note: this is my current hard-blocker. I can't progress without this.

Situation:

-------------------
In C++:

class Base
{
  virtual ~Base() {}
  size_t x;
};

class Interface
{
  virtual void A() = 0;
  virtual void B() = 0;
  virtual void C() = 0;
  virtual void Method() = 0;
};

class Derived : public Base, public Interface
{
  size_t y;
};

-------------------
D:

extern(C++) class Base
{
  ~this() {}
  size_t x;
}

extern(C++) interface Interface
{
  void A();
  void B();
  void C();
  void Method();
}

extern(C++) class Derived : Base, Interface
{
  size_t y;
}

-------------------

This code should work.


In C++, Derived is laid out:
{
  void *__Base_vtable;
  size_t x;
  void *__Interface_vtable;
  size_t y;
}

This is as I expect.

In D, according to the debuginfo output by DMD, Derived is reported as:
{
  void *__Base_vtable;
  size_t x;
  size_t y;
}

* The actual binary may not match the debuginfo; I didn't check, but there is some evidence for this.

Surprisingly, this compiles, but calling Method generates wrong code:

00007FF72DB7381B  mov         rbx,qword ptr [this]
00007FF72DB7381F  mov         rcx,qword ptr [rbx+10h]  // rcx is now
__Interface_vtable!
00007FF72DB73823  mov         rcx,qword ptr [rcx]
00007FF72DB73826  sub         rsp,20h
00007FF72DB7382A  mov         rax,qword ptr [rcx]
00007FF72DB7382D  call        qword ptr [rax+18h]  // 18h is the
offset of Method, rax is wrong. [[rbx+10h]+18h] is the correct call.

We load rbx = [this], then we load rcx = [rbx+10h]. This looks good,
[rbx+10h] is the correct offset of __Interface_vtable in C++, even
though the debuginfo claims that's the offset of 'y'.
Then it gets weird; rcx = [rcx], this is effectively getting the first
function pointer in the vtable; A().
Then further compounding with rax = [rcx], loading the first 8 bytes
of program code from the function A()!
Finally it calls [rax+18h]. If rax were still __Interface_vtable, 18h
is the correct offset of the function I'm calling (Method), and it was
correct after the second opcode, but those 2 weird dereferences broke
it.

Hoping this can be supported, I can't move forward without this.
January 19, 2016
On 19/01/2016 4:10 PM, Manu via Digitalmars-d wrote:
> I'm repeating this here from the depths of my prior whinge thread,
> since this is kind of a new topic.
>
> D's multiple inheritance solution is single-inheritance + interfaces.
> Rightly so, it's a great solution, and this matches what all the C++
> programmers I've ever worked with do anyway. Trouble is, it doesn't
> seem to work with extern(C++) at the moment.
>

Yeah, it never has.  No attempt has ever been made to make it work.

If you want to take a look, it's probably not much more complicated than fixing the layout.  The code should mostly be somewhere in todt.c (when ClassDeclaration::cpp is non-zero).
January 19, 2016
On 1/19/2016 12:34 AM, Daniel Murphy wrote:
> Yeah, it never has.  No attempt has ever been made to make it work.

Actually, as I recall it was made to match what DMC++ generates for Win32.

January 19, 2016
On 01/19/2016 03:34 AM, Daniel Murphy wrote:
> On 19/01/2016 4:10 PM, Manu via Digitalmars-d wrote:
>> I'm repeating this here from the depths of my prior whinge thread,
>> since this is kind of a new topic.
>>
>> D's multiple inheritance solution is single-inheritance + interfaces.
>> Rightly so, it's a great solution, and this matches what all the C++
>> programmers I've ever worked with do anyway. Trouble is, it doesn't
>> seem to work with extern(C++) at the moment.
>>
>
> Yeah, it never has.  No attempt has ever been made to make it work.
>
> If you want to take a look, it's probably not much more complicated than
> fixing the layout.  The code should mostly be somewhere in todt.c (when
> ClassDeclaration::cpp is non-zero).

Is there an open issue? -- Andrei
January 20, 2016
On 19 January 2016 at 22:36, Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> Is there an open issue? -- Andrei

There is: https://issues.dlang.org/show_bug.cgi?id=15579
January 19, 2016
On 01/19/2016 09:02 AM, Manu via Digitalmars-d wrote:
> On 19 January 2016 at 22:36, Andrei Alexandrescu via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>>
>> Is there an open issue? -- Andrei
>
> There is: https://issues.dlang.org/show_bug.cgi?id=15579

Thanks, awesome. I've noticed this a while ago, but slipped off my mind before I reported it. -- Andrei

January 19, 2016
On Tuesday, 19 January 2016 at 15:25:53 UTC, Andrei Alexandrescu wrote:
> On 01/19/2016 09:02 AM, Manu via Digitalmars-d wrote:
>> On 19 January 2016 at 22:36, Andrei Alexandrescu via Digitalmars-d
>> <digitalmars-d@puremagic.com> wrote:
>>>
>>> Is there an open issue? -- Andrei
>>
>> There is: https://issues.dlang.org/show_bug.cgi?id=15579
>
> Thanks, awesome. I've noticed this a while ago, but slipped off my mind before I reported it. -- Andrei

For reference: https://mentorembedded.github.io/cxx-abi/abi.html#vtable
January 20, 2016
On 19/01/2016 8:04 PM, Walter Bright wrote:
> On 1/19/2016 12:34 AM, Daniel Murphy wrote:
>> Yeah, it never has.  No attempt has ever been made to make it work.
>
> Actually, as I recall it was made to match what DMC++ generates for Win32.
>

Wasn't that from before we had extern(C++) classes?  I did the extern(C++) single inheritance class layout but didn't touch interfaces.
January 19, 2016
On 1/19/2016 1:59 PM, Daniel Murphy wrote:
> On 19/01/2016 8:04 PM, Walter Bright wrote:
>> On 1/19/2016 12:34 AM, Daniel Murphy wrote:
>>> Yeah, it never has.  No attempt has ever been made to make it work.
>>
>> Actually, as I recall it was made to match what DMC++ generates for Win32.
>>
>
> Wasn't that from before we had extern(C++) classes?  I did the extern(C++)
> single inheritance class layout but didn't touch interfaces.

We had COM, which was an earlier form of C++ class support.
January 22, 2016
On Wednesday, 20 January 2016 at 00:45:34 UTC, Walter Bright wrote:
> On 1/19/2016 1:59 PM, Daniel Murphy wrote:
>> On 19/01/2016 8:04 PM, Walter Bright wrote:
>>> On 1/19/2016 12:34 AM, Daniel Murphy wrote:
>>>> Yeah, it never has.  No attempt has ever been made to make it work.
>>>
>>> Actually, as I recall it was made to match what DMC++ generates for Win32.
>>>
>>
>> Wasn't that from before we had extern(C++) classes?  I did the extern(C++)
>> single inheritance class layout but didn't touch interfaces.
>
> We had COM, which was an earlier form of C++ class support.

BTW, in docs I saw the following example:
Calling D Virtual Functions From C++

```
Given D code like:

extern (C++) int callE(E);

extern (C++) interface E
{
    int bar(int i, int j, int k);
}

class F : E
{
    extern (C++) int bar(int i, int j, int k)
    {
        writefln("i = %s", i);
        writefln("j = %s", j);
        writefln("k = %s", k);
        return 8;
    }
}

void main()
{
    F f = new F();
    callE(f);
}
```

```
The C++ code to access it looks like:

class E
{
  public:
    virtual int bar(int i, int j, int k);
};


int callE(E *e)
{
    return e->bar(11,12,13);
}
```


In this example C++ class E hasn't fields and another stuff. What happens if I change E?

class E
{
  std::string s;
  public:
    virtual int bar(int i, int j, int k);
    int strageHash()
    {
         return s.length() + bar(0, 0, 0);
    }
};

int callE(E *e)
{
    return e->strageHash();
}

AFAIK, D can't generate correct F layout. D doesn't know sizeof(E), D doesn't know E ctor (the second one is fixable).
As result, new F() object can be smaller that E and this code has an unexpected behaviour.
Ok, we aren't gods and we can't suggest something better (exclusive of moveing multiple inheritance and C++ layout to D :).
However we may and should alert user about this limitation and about another limitations like this.
And when we add a new C++-related feature, we should declare C++-side limitations, in the first place, because they can't be enforced by D compiler.

And have someone any ideas about C++ to D interface generator?




« First   ‹ Prev
1 2 3