Simpler placement new

it’s very difficult to tell when moves might still happen internally in the expression being evaluated

This seems like the perfect being the enemy of the good. Right now there's no solution at all. I can understand not making large language changes when they don't sufficiently solve the problem, but having a single function documented as having slightly special behavior seems pretty harmless, even if authors have to be very careful to get the benefits of it. (In fact, even with no language changes at all, you would get some of the benefits today in Release builds--that's what the boxext crate does; this proposal could be viewed as just making that existing solution more reliable.)

I'm really asking about point #4 in Placement NWBI<- FAQ (New/Box/In/Left Arrow). That point explains why just guaranteeing optimization of Vec::push is inadequate, but it doesn't say why the alternative has to be a language extension. All of the other discussion seems to take as given that a language change is required, and so there's an appropriately high bar for the usability of the result. I think the bar can be a lot lower if it's not a major change, just one new special function.

And the problem you've described (making it more obvious when moves / temp allocations might happen) is orthogonal to the problem of having some way to construct into a designated storage location. I think a solution to that would look more like a Move trait, which (much like Sized) would be auto-added to all trait bounds, but functions could opt-out via ?Move.

Then you could have things like Vec::push_with<T: ?Move, F: FnOnce()->T>(src: *mut T, f: F), which guarantees that push_with doesn't introduce an extra move.

(I think ?Move has been rejected before because there's too little benefit and, but this seems like a catch-22: placement new is wanted, but it needs more predictable guarantees. But the language doesn't have a way to talk about those guarantees, so one would need to be added. But we don't want to add one, because there's not enough need to justify it.)

...

The Result situation is different. Here it's not about obvious vs. subtle behavior; there's a clearly desirable goal (efficient combination of placement new with idiomatic error handling) that's hard to achieve. Again, I think that's a good argument against a major change, but not against a relatively trivial change that doesn't preclude any future proposals.

If Result someday got a special ABI repr (e.g. as suggested in issue 42047 where f() -> Result<T,E> would be compiled as something like f(_0: *mut T, _1: *mut E) -> bool, then you could expose it to container lib authors in a similar way:

ptr::write_result_with<T,E,F>(dst: *mut T, f: F) -> Result<(), E>
    where F: FnOnce() -> Result<T,E>

which would be enough to build e.g. Vec::try_push_with() that could push an Ok result without extra temporary space for a T.

(I left Result out the original post because I didn't want to derail the thread--I'm not advocating for or against anything to do with Result, just observing that using closures for placement new is compatible with future changes along those lines.)