On Tue, Apr 16, 2024 at 10:51 AM Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Tue, Apr 16, 2024 at 12:08 PM Frederick Virchanza Gotham wrote:
> On the Microsoft compiler, we really need to test it with the following class:
>     class Base { int i, j; }
>     class Derived : public Base { virtual ~Derived(void){} };
> An object of type 'Derived' will be laid out in memory by the
> Microsoft compiler as follows:
>     - - -  4 bytes = i
>     - - -  4 bytes = j
>     - - -  8 bytes = pointer to vtable

I know some of you don't want me reverse-engineering Microsoft's
compiler here on the mailing list but we need to find out if this can
be implemented without an ABI break. So I fed the following into
Visual Studio 2022:

No one really cares about whether you're doing reverse engineering or not.

The thing is that these low-level implementation details are the least interesting part of the proposal, and most papers include much less low-level implementation detail than you seem to want to give. Put a small amount of detail in the paper if you feel it's necessary in order to convince people that the proposal is implementable. Then, focus most of your time and energy on writing the motivation section. Then, submit the paper. Sending us these messages that go into gory amounts of detail about the Microsoft ABI is just a form of procrastination from the work that actually needs to be done, and no one is reading them.

    struct A {
        int a, b;

    struct B {
        float c, d;
        virtual ~B(void){}

    struct Donkey : A, B {
        double d;

    Donkey d;

    void Func(void) noexcept(false)
        throw d;

Then I hit Ctrl + Alt + D to see the assembler generated for 'Func' as follows:

    1: sub         rsp,48h
    2: lea         rdx,[d]
    3: lea         rcx,[rsp+20h]
    4: call        Donkey::Donkey
    5: lea         rdx,[_TI3?AUDonkey@@]
    6: lea         rcx,[rsp+20h]
    7: call        _CxxThrowException

which can be explained line by line as follows:

    1: Allocate 72 bytes on the stack
    2: Set 2nd argument to address of 'd'
    3: Set 1st argument to address of 40 bytes of stack space
    4: Invoke the copy-constructor of Donkey with above two arguments
    5: Set 2nd argument to address of ThrowInfo for Donkey
    6: Set 1st argument to address of cloned object on the stack
    7: Call _CxxThrowException with above two arguments

We can convert the above 7 instructions to the following C++ code:

    void Func(void) noexcept(false)
        char stack_space[72u];  // Allocate space on the stack
        ::new(stack_space + 32) Donkey(&d);  // Create a cloned object
        _CxxThrowException( stack_space + 32, __get_throw_info(Donkey)
);  // Throw an exception

We can see the function signature of _CxxThrowException on the MSDN
website as follows:

    void _CxxThrowException( void *pExceptionObject,  ThrowInfo *pThrowInfo );

There is something promising here: The function '_CxxThrowException'
is not passed the address of the vtable pointer inside Donkey, and
therefore it must be getting it from the ThrowInfo struct.

So to summarise: It will be possible to implement this on the
Microsoft compiler for any class type (including the most complex
cases of virtual multiple inheritance) so long as we can utilise the
'type_info' to get the 'ThrowInfo'.

So the missing piece now is just to come up with a function as follows:

    ThrowInfo const *get_ThrowInfo_from_type_info(type_info const*);

I'm confident that this can be implemented, because if you look at the
signature of "__RTDynamicCast", it's able to perform a 'dynamic_cast'
using only the 'type_info'. So there must be a link from the type_info
to either:
    (a) RTTICompleteObjectLocator
    (b) ThrowInfo

And there's probably a link from RTTICompleteObjectLocator to
ThrowInfo. I'll disassemble "__RTDynamicCast" and try to find out how
Microsoft is doing it, and come up with an implementation of
std::any::base that works properly in every scenario.
Std-Proposals mailing list

Brian Bi