C++ Logo

std-proposals

Advanced search

Re: [std-proposals] declfunc - parameters deduced from arguments

From: Thiago Macieira <thiago_at_[hidden]>
Date: Thu, 06 Jun 2024 14:41:01 -0700
On Thursday 6 June 2024 13:25:30 GMT-7 Frederick Virchanza Gotham via Std-
Proposals wrote:
> On Thu, Jun 6, 2024 at 1:08 AM Thiago Macieira wrote:
> > 1) on 32-bit MSVC, are constructors and destructors
> >
> > __cdecl or __thiscall?
>
> It's literally only 32-Bit x86 that passes the 'this' pointer in
> anything other than the position of the first parameter. No other
> combination of instruction set and operating system does that. As for
> whether it's __cdecl or __thiscall, it should be the same as for any
> other member function.

But is it? The whole point was to check the assumption on whether it is,
because if the constructor is a member function but isn't called *like* a
member function, then it can't be used in a PMF. And if the question is even
valid for MSVC x86 can have this, it's possible it is too for other, more
obscure architectures that C++ is still supported on. Therefore, the paper
needs an exhaustive approval from all vendors before being accepted.

(it's __thiscall)

The other problem is, of course, that you're using a PMF not an object, but on
storage area whose lifetime hasn't begun yet. That violates the current
requirements for .* and ->*

> > 2) on IA-64 C++ ABI, the base constructors (mangling "C2") have an extra
> > parameter passed implicitly, which is a pointer to the virtual-table-in-
> > construction (a "TC" symbol). There's no way that user code could ever
> > call this constructor.
>
> This hadn't crossed my mind. But I at least think that destructors
> should have an address. They're only ever implemented as
> "void(*)(void*)", right?

No, the closest would be void (Klass:: *)() (remember __thiscall), because
this-pointer adjustment and virtual selection would also be required.

In any case, there's already a syntax to call a destructor on an object. Why
do we need another? If you want to type-erase that, a lambda is a few
keystrokes away.

> (i.e. the sole argument is the 'this'
> pointer). I tried compiling the following template function:
>
> template<typename T>
> void destroy(T &arg)
> {
> arg.~T();
> }
>
> with the T set to S:
>
> struct S {
> ~S(void) __attribute__((noinline)) { std::cout << "goodbye\n"; }
> };
>
> And the assembler for "destroy<S>" came out as:
>
> e9 db ff ff ff jmp 0xffffffffffffffe0

Ignoring the nonsensical address it printed (that has to be an operator
error), that's just a tail-call. Being able to extract the pointer to the
destructor's entry point saves us the 16 sharable and read-only bytes of this
thunk.

> If I change it to a virtual destructor, it comes out as:
>
> 48 8b 07 mov rax,QWORD PTR [rdi]
> ff 20 jmp QWORD PTR [rax]

> I reckon on every CPU, operating system and compiler, destructors are
> just functions that take a 'this' pointer and return void.

Again, not necessarily. Because they've never been directly callable, it's
possible some implementation did weird things with it. I don't think it's
likely, but it's possible.

Considering I am seeing a near-zero value for this functionality, I don't see
why we should have it.

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
  Principal Engineer - Intel DCAI Fleet Engineering and Quality

Received on 2024-06-06 21:41:10