<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [Microsoft ABI] dllexport not sufficient to emit complete destructor"
   href="https://bugs.llvm.org/show_bug.cgi?id=44205">44205</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[Microsoft ABI] dllexport not sufficient to emit complete destructor
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>LLVM Codegen
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>CFSworks@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org, neeilans@live.com, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>In the Microsoft ABI, non-base destructors are treated as if they were inline
methods, being emitted only as-needed. The exception to "only as-needed" is if
there's a dllexport, which forces all inlines to be emitted so that they're
available to a dllimport, as the latter altogether suppresses emitting
definitions in favor of importing them from a DLL containing the dllexport
counterpart.

Clang views complete destructors as a tier below inline methods: their
definitions aren't just elided, they aren't even brought into existence unless
needed somewhere in the TU. Perfectly okay, but if the class is dllexport, then
the complete destructor must be considered "needed" (must be realized) so it
can be emitted.

For the benefit of those searching for this bug, the missing vbase dtor will
cause an error that looks like:
lld-link : error : undefined symbol: "__declspec(dllimport) public: void
__cdecl SomeClass::`vbase dtor'(void)" (__imp_??_DSomeClass@@QEAAXXZ)

One suitable workaround is to put a never-called function in the dllexport TU
that somehow references the complete destructor. Another is to enable the
inline optimization in the dllimport TU; that should cause Clang to inline the
complete destructor instead of importing it.

Distinct from, but perhaps related to, #44035, which is caused by the complete
destructor using the dllimport/dllexport declaration from the base destructor
instead of from the class declaration.

BUG REPRO:

$ cat dllexport.cpp 
struct Base { ~Base() { } };
struct __declspec(dllexport) Exported : virtual public Base { };

$ cl /nologo /c dllexport.cpp && dumpbin /symbols dllexport.obj | grep vbase
dllexport.cpp
01D 00000000 SECTA  notype ()    External     | ??_DExported@@QEAAXXZ (public:
void __cdecl Exported::`vbase destructor'(void))

$ clang-cl /nologo /c dllexport.cpp && dumpbin /symbols dllexport.obj | grep
vbase

$</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>