[Issue 21690] Unable to dynamic cast extern(C++) classes

d-bugmail at puremagic.com d-bugmail at puremagic.com
Thu Jun 1 14:10:18 UTC 2023


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

Bolpat <qs.il.paperinik at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |qs.il.paperinik at gmail.com

--- Comment #14 from Bolpat <qs.il.paperinik at gmail.com> ---
(In reply to kinke from comment #1)
> So while getting proper dynamic casts working is probably quite hard, we
> could probably disallow downcasts like this and require an explicit static
> cast (`cast(CC) cast(void*) ca`)?

In C++ terminology at least, this isn’t a `static_cast`, but a
`reinterpret_cast`. It works when you only have single inheritance (counting
interfaces as inheritance as well). As soon as any form of multiple inheritance
(including interfaces) enters the picture, `cast(void*)` won’t do what you
want. There are simple, but relevant, pointer value adjustments at play.

Example:
```d
import std.stdio;
extern(C++) abstract class B { int x; abstract void f(); }
extern(C++) interface I { void g(); }
extern(C++) class D : B, I
{
    override void f() => writeln("f");
    override void g() => writeln("g");
}

void main()
{
    D d = new D;
    void* bptr = cast(void*) cast(B) d;
    void* iptr = cast(void*) cast(I) d;
    assert(bptr !is iptr); // passes

    void* vptr = cast(void*) d;
    B b = cast(B) vptr;
    I i = cast(I) vptr;
    b.f(); // prints f as expected
    i.g(); // should print g, on run.dlang.org, prints f as well
}
```
The `extern(C++)` has little to do with it; with `extern(D)` the problems
persist.

As far as I know, for class handles, it’s syntactically impossible to express a
C++ `static_cast` in D; it’s a `dynamic_cast` or – if you go via `void*` – it’s
a `reinterpret_cast`. Of course, a derived-to-base `dynamic_cast` can be
optimized to be a `static_cast`, but there’s no way to tell the compiler: I
*know* this base-class object is in fact a derived object, so adjust the
pointer accordingly (and don’t check TypeInfo or whatever and give me UB if I’m
wrong).
A simple solution would be to introduce `static cast(Type) UnaryExpression` for
that. It would be valid only if `Type` and the type of `UnaryExpression` are
both a class or interface type, which have a unique inheritance relationship.

--


More information about the Digitalmars-d-bugs mailing list