I think this is infeasible and also the wrong way of thinking about FFI.
For something like #[repr(C++)] to be feasible, Rust’s type system would have to be able to represent every detail of C++'s type system. That is not only not a reasonable design goal for the language, it’s not even a desirable design goal; we actively want to be able to look at a C++ type-system feature and say “no, that is a bad feature and we are not copying it.”
#[repr(C)] is feasible only because C’s type system is simple enough that it does make sense to clone every detail of it, and you’ll note that there are still lacunae, e.g. last I checked transparent unions of structures were still not available, making it impossible to work with certain system APIs in Rust.
ABI-level annotations like the proposed #[pass_by(invisible_reference)] are feasible for the same reason #[repr(C)] is feasible: the possibility space is simple and orthogonal. There are only so many ways to pass arguments around, and only so many ways to lay out aggregate types in memory. (I would like to see Rust grow something like Ada’s representation clauses, in the long term.) But they’re also the right way to think about FFI, because they give you direct control over the properties that actually matter for interop. If you observe that
struct Bar {
size_t data;
~Bar() { data = 0; }
};
needs to be passed by invisible reference, you can just toggle that property on the Rust shim structure; you don’t have to know why pass-by-value is unwanted.
It’s true that low-level annotations don’t directly solve the problem of FFI interaction with C++. Something, or someone, has to track all the details of the C++ ABI and work out which annotations to apply to which shim structures. To some extent my strategy just moves the complexity from rustc to bindgen, but I’d argue that bindgen is the right place for it.