Thread overview
[Issue 20082] Struct with extern destructor that's never called causes link error
Jul 25, 2019
Rainer Schuetze
Jul 25, 2019
Manu
Jul 25, 2019
kinke
Jul 25, 2019
Manu
Jul 25, 2019
Rainer Schuetze
Jul 25, 2019
Manu
Jul 25, 2019
kinke
Jul 26, 2019
Rainer Schuetze
Jul 26, 2019
Manu
Dec 17, 2022
Iain Buclaw
July 25, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

Rainer Schuetze <r.sagitario@gmx.de> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |r.sagitario@gmx.de
           Hardware|x86_64                      |All
                 OS|Windows                     |All

--- Comment #1 from Rainer Schuetze <r.sagitario@gmx.de> ---
The problem is that the dtor is referenced by the TypeInfo for S and that the MS linker doesn't eliminate the reference to it before removing unused COMDATs due to the default /OPT:REF. optlink is more aggressive and works the other way araound.

Even if the MS linker behaved the same, the default for /DEBUG builds is /OPT:NOREF so the issue would reappear, and more so with debug info generation (optlink also reports the unresolved symbol in that case).

The online compiler (probably linux) also reports an unresolved symbol, so the problem is not Windows specific.

For the MS linker, a workaround might be to add a pragma(linkerDirective, "/ALTERNATENAME:...") to weakly redirect the symbol to a dummy function.

--
July 25, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

--- Comment #2 from Manu <turkeyman@gmail.com> ---
I suspected the TypeInfo, but shouldn't that only contain destructor for
classes?
In my case, the struct is extern(C++) too, which means the D TypeInfo shouldn't
even exist?

--
July 25, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

kinke <kinke@gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |kinke@gmx.net

--- Comment #3 from kinke <kinke@gmx.net> ---
(In reply to Manu from comment #2)
> I suspected the TypeInfo, but shouldn't that only contain destructor for classes?

Nope, it's needed to implement the `destroy(void*)` method.

> In my case, the struct is extern(C++) too, which means the D TypeInfo
> shouldn't even exist?

That seems to be a common misconception. Without D TypeInfo, you'd lose the ability to have dynamic arrays of that extern(C++) struct, associative arrays with that struct as key type etc. etc.

--
July 25, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

--- Comment #4 from Manu <turkeyman@gmail.com> ---
(In reply to kinke from comment #3)
> (In reply to Manu from comment #2)
> > I suspected the TypeInfo, but shouldn't that only contain destructor for classes?
> 
> Nope, it's needed to implement the `destroy(void*)` method.

What is that? I don't want it...

> > In my case, the struct is extern(C++) too, which means the D TypeInfo
> > shouldn't even exist?
> 
> That seems to be a common misconception. Without D TypeInfo, you'd lose the ability to have dynamic arrays of that extern(C++) struct,

Why?

> associative
> arrays with that struct as key type etc. etc.

Why?

--
July 25, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

--- Comment #5 from Rainer Schuetze <r.sagitario@gmx.de> ---
> Nope, it's needed to implement the `destroy(void*)` method.

I don't think it is needed for destroy, the dtor can be called directly.

>>Without D TypeInfo, you'd lose the ability to have dynamic arrays of
>> that extern(C++) struct, associative arrays with that struct as key
>> type etc. etc.

> Why?

It doesn't have to, but that's how dynamic and associative arrays are currently implemented. There's a GSoC project trying to reduce that dependency.

The typeinfo is also needed to finalize structs that are allocated on the GC heap.

--
July 25, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

--- Comment #6 from Manu <turkeyman@gmail.com> ---
Well... there's no way to extern to a struct in that case. What's the workaround?

--
July 25, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

--- Comment #7 from kinke <kinke@gmx.net> ---
(In reply to Manu from comment #6)
> Well... there's no way to extern to a struct in that case. What's the workaround?

Well, define 'to extern'. How is the missing C++ implementation supposed to be there at link-time if I'm allocating a struct on the D side and need the dtor? E.g., is there a dependency on a certain C++ lib when importing your D module, or is the struct just designed to be allocated on the C++ side and passed by ref/pointer to the D side? In the latter case, you could annotate the dtor on the D side with @disable.

--
July 26, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

--- Comment #8 from Rainer Schuetze <r.sagitario@gmx.de> ---
> What's the workaround?

If you can assume that the dtor is supplied as soon as you actually use the struct, this could work on Windows:

struct S
{
    ~this();
}

void dummyDtor()
{
    // dtor not linked in!
    assert(false);
}

pragma(linkerDirective, "/ALTERNATENAME:" ~ S.__dtor.mangleof ~ "=" ~
dummyDtor.mangleof);

IIRC there is some other way on Posix to get weak linkage.

--
July 26, 2019
https://issues.dlang.org/show_bug.cgi?id=20082

--- Comment #9 from Manu <turkeyman@gmail.com> ---
Mmm. I could use weak linkage, feels like a massive hack though. Situation is not-great.

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=20082

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P2

--