This is a very early draft, mostly looking for direction/guidance at this point (notably whether the cost/benefit ratio of the overall idea is sensible).
I need to do a lot of refactors, some (a lot of) tests, etc.
std::move/std::forward are just casts, and are used a lot (230K instances in the VCPKG repository for std::move).
This code some issues:
- Worse debug experience
- More symbols
- Slower build times through template instantiations
- Worse Codegen
push rbp mov rbp, rsp sub rsp, 16 mov dword ptr [rbp - 4], edi lea rdi, [rbp - 4] call std::remove_reference<int&>::type&& std::move<int&>(int&) mov eax, dword ptr [rax] add rsp, 16 pop rbp ret
These functions could be marked force inline, but that does not address the build time concerns, and it doesn't solve O0 (some people seem to care?)
I also consider an LLVM pass to replace calls to std::move/std::forward, but that doesn't solve build time concerns.
In the end, I landed on the idea to replace these calls by a cast expression in the front end.
The general idea is to try to intercept qualified calls before overload resolution, and after overload resolutions for all calls.
The functions are still required to be declared, so lookup is not modified.
When a replacement fails, we try to create the CallExpr as usual so any diagnostic is emitted from there.
The intent is of course that this replacement cannot be observable.
- Is this an avenue worth pursuing ?
- Do we want an even more generic solution so that calls to eg, is_constant_evaluated can be replaced too?
- Do we want to expand to as_const, to_integer, to_underlying, bit_cast?
In terms of AST nodes, do we want to preserve the original replaced expression?
My current CXXStdLibraryCastExpr assumes the call is resolved to a CallExpr, but that's no longer the case since I also replace calls before template instantiations,
so I would probably do something to keep the arguments.
I don't know how much information we need to retain, and as is certainly very visible, I have no idea what I am doing.
Nevertheless, I figured the path might be in a good enough state to start a discussion.
I am also thinking that making std::forward(x) or std::fwd(x) (notice the lack of angle brackets) a magic expression in C++23 using the same mechanism might be worth pursuing.
(instead of new syntax as in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0644r1.html)