C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Custom call convention per type

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Fri, 29 Jul 2022 11:27:32 +0200
pt., 29 lip 2022 o 00:48 Jason McKesson via Std-Proposals
<std-proposals_at_[hidden]> napisaƂ(a):
>
> On Thu, Jul 28, 2022 at 5:26 PM Marcin Jaczewski via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > Currently there are multiple problems linked to lifetime of function parameters.
> > Simply current default behavior does not fit all corner cases.
> >
> > Example is `std::unique` that generates subpar code because the call
> > site is a firewall that
> > prevents the compiler to see at once destructor and move operation.
>
> I don't understand what you mean by this. Are you talking about the
> movement of the elements in the range, since the destruction of the
> moved-from elements (if it happens at all) is handled by the
> (eventual) caller? If so, your suggestion can't solve that problem.
> The problem you're describing is not about parameters; it's about the
> *contents* of those parameters.
>

Yes, this is about content of parameters but handling of destructors
interfire with this.
As different code move data and different code delete it.

> > Now what if we op-in to allow a given type to have lifetime handled differently?
> >
> > Image we add new contextual keyword like:
> > ```
> > class Type arg_destructor_in_callee
> > {
> > };
> > ```
> > Now when the function `void foo(Type arg)` is called, the object `arg`
> > will be destroyed
> > in the body of `foo` not by the caller. This will make for compiler
> > easy to see if object was
> > moved before the destructor call and then if the destructor was inlined
> > then it could remove it all. This will work great with `bitcopies` or
> > `Trivially Relocatable` types.
>
> First, making this a property of the type instead of the function
> makes no sense. After all, the problem is caused (I guess?) by what
> the function is doing. This is not something inherent to the nature of
> an object type; it's a part of how an object is being used.
>
> Second, this is yet another "trivially relocatable" proposal in yet
> another disguise. I really wish people would stop trying to break this
> problem down into little bits in the hopes that they can sneak one of
> them past the committee.
>

Yes, not directly "trivially relocatable" but more support/synergy for
this proposal.

> > This will of course affect ABI (this is why keyword not attribute) and
> > change order of destructor calls.
> > This could be new reference type (`&&&`??) but this probably will be
> > big burden on all generic
> > code as we will need another case to handle this.
>
> Oh, that's why you want it on the type. So that you can dodge the
> forwarding problem.
>

Exactly, in theory it should be a new reference type but right now it has an
exponential explosion of all possible combinations of parameter types.
Adding new makes it a lot worse.

> > Another interesting side effect is that even if this feature need
> > op-in you can always wrap arbitrary object into type with this did
> > this and benefice from this, like:
> >
> > ```
> > template<typename T>
> > struct Wrapper arg_destructor_in_callee
> > {
> > Wrapper (T&& t) : data{ std::move(t) } //implicit constructor
> > {
> > }
> > T data;
> > };
> > template<typename T>
> > void foo(Wrapper<T> arg)
> > {
> > }
> >
> > int main()
> > {
> > foo(1);
> > foo(std::make_unique<int>());
> > }
> > ```
> > And no destructor will be directly called by `main`.
>
> So really, you could do this purely as a library feature. You fashion
> a type called "internal_relocate<T>" or somesuch which is
> constructible from a `T`. But its destructor doesn't call the
> destructor of the `T` it holds. It's up to the implementation of the
> function to invoke the destructor by using a member of
> `internal_relocate` or somesuch. And any function which wants to take
> advantage of this would take an `internal_relocate` object as a
> parameter.
>

but this library solution can't work correctly without making hole in
the lifetime system.
user need to remember to correctly move object from this parameter
otherwise he will have UB.

My idea is to make this problem a local one, where functions see both
destructor and move operation.
If both are not inlined function then there will be no difference
compared to current state,
but if its inlined or `bitcopy` is included in standard, the compiler
can remove destructor code.



> > And this brings me to the opposite problem, that in some cases I do
> > not want to temporarily be destroyed by callee.
>
> What does that mean? Parameters to a function don't get destroyed "by
> the callee". Ever. If you're talking about the return value, then
> there are already proposals to allow for named RVO, though they have
> (reasonable) limits on the usage of the return value object.
>

No, this is more a digression, as standard do not specify who exactly
is responsible for
destruction of value parameters. If I recall correctly MSVC do use
effective `arg_destructor_in_callee`
but other like GCC do not. And there could be cases where I would like
to have GCC behavior in MSVC.

Or simply when someone used `arg_destructor_in_callee` but for some
reason I do not want this behavior
in my function and would like to have an escape hatch in the form of a
wrapper that behaves in the opposite way.


> > Then we could define
> > another keyword `arg_destructor_in_caller` that would force all ABI to
> > pass this temporary as a hidden pointer.
> >
> > Would this approach be useful?
> > --
> > Std-Proposals mailing list
> > Std-Proposals_at_[hidden]
> > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2022-07-29 09:27:42