<html>
    <head>
      <base href="https://llvm.org/bugs/" />
    </head>
    <body><span class="vcard"><a class="email" href="mailto:rnk@google.com" title="Reid Kleckner <rnk@google.com>"> <span class="fn">Reid Kleckner</span></a>
</span> changed
              <a class="bz_bug_link 
          bz_status_RESOLVED  bz_closed"
   title="RESOLVED INVALID - novtable support"
   href="https://llvm.org/bugs/show_bug.cgi?id=26905">bug 26905</a>
        <br>
             <table border="1" cellspacing="0" cellpadding="8">
          <tr>
            <th>What</th>
            <th>Removed</th>
            <th>Added</th>
          </tr>

         <tr>
           <td style="text-align:right;">Status</td>
           <td>NEW
           </td>
           <td>RESOLVED
           </td>
         </tr>

         <tr>
           <td style="text-align:right;">CC</td>
           <td>
                
           </td>
           <td>rnk@google.com
           </td>
         </tr>

         <tr>
           <td style="text-align:right;">Resolution</td>
           <td>---
           </td>
           <td>INVALID
           </td>
         </tr></table>
      <p>
        <div>
            <b><a class="bz_bug_link 
          bz_status_RESOLVED  bz_closed"
   title="RESOLVED INVALID - novtable support"
   href="https://llvm.org/bugs/show_bug.cgi?id=26905#c1">Comment # 1</a>
              on <a class="bz_bug_link 
          bz_status_RESOLVED  bz_closed"
   title="RESOLVED INVALID - novtable support"
   href="https://llvm.org/bugs/show_bug.cgi?id=26905">bug 26905</a>
              from <span class="vcard"><a class="email" href="mailto:rnk@google.com" title="Reid Kleckner <rnk@google.com>"> <span class="fn">Reid Kleckner</span></a>
</span></b>
        <pre>Your program is working because MSVC aggressively devirtualizes method calls in
constructors. Consider this reduction and the code generated by both compilers:

$ cat t.cpp
struct __declspec(novtable) A { A(); virtual void Init() = 0; };
struct __declspec(novtable) B : A { B(); void Init(); };
B::B() { this->Init(); }
$ clang -S t.cpp  -o -
...
        movq    %rcx, 48(%rsp)
        movq    %rcx, 40(%rsp)          # 8-byte Spill
        callq   "??0A@@QEAA@XZ"
        movq    40(%rsp), %rcx          # 8-byte Reload
        movq    (%rcx), %rdx
        movq    (%rdx), %rdx
        movq    %rax, 32(%rsp)          # 8-byte Spill
        callq   *%rdx
$ cl -c t.cpp -Facl.asm && cat cl.asm
...
        mov     QWORD PTR [rsp+8], rcx
        sub     rsp, 40                                 ; 00000028H
        mov     rcx, QWORD PTR this$[rsp]
        call    ??0A@@QEAA@XZ                           ; A::A
        mov     rcx, QWORD PTR this$[rsp]
        call    ?Init@B@@UEAAXXZ                        ; B::Init
        mov     rax, QWORD PTR this$[rsp]
        add     rsp, 40                                 ; 00000028H
        ret     0

The difference is that Clang's constructor for IteratedHashWithStaticTransform
is doing a virtual call for IteratedHashWithStaticTransform::Init, instead of
doing a direct call. If you annotate this class with declspec(novtable), then
the vptr slot is not initialized, and you will crash.

To me, the user is misusing novtable by applying it to a non-abstract class. If
you changed the source program slightly to invoke another virtual method from
within 'Init', your program would crash with MSVC as well.</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>