From e6491ddfc72af80594c2020659c6e3db43bb753c Mon Sep 17 00:00:00 2001 From: Charlie Barto Date: Sun, 30 Oct 2022 15:51:09 -0700 Subject: [PATCH] Replace confusing note in cpp.md on "RVO" The original commit adding this note referenced #778, but then went on to talk about how the problem was RVO and that the problem is not possible to solve in bindgen because bindgen can't know if RVO happened or not. However this is incorrect in several ways. The problem in #778 has nothing whatsoever to do with RVO but rather with bindgen simply not understanding the calling convention for passing or returning types that are "non trivial for the purposes of calls". This is completely consistent and does not depend on what the optimizer decided to do (after all, if callsite side calling-convention did depend on what the optimizer happened to do inside the function it would be impossible for C++ compilers to emit correct calls to external C++ functions!). You can see this quite clearly [here](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGIM6SuADJ4DJgAcj4ARpjEEgDspAAOqAqETgwe3r7%2ByanpAiFhkSwxcVyJdpgOGUIETMQEWT5%2BAVU1AnUNBEUR0bEJtvWNzTltwz2hfaUDFQCUtqhexMjsHAD06wDUACoAnkmYW3tLxFtoWFsIsZikWyRbtKhM6FuGW5iqrEn0AHQmGgAggoCMQvA4tgRMCCokwlFsTPErPEACImADMViBILBEKhIIRSIBgK2pMh0IIEDmGKxJLJ%2BMpaAYBIZ5gAbNTMcSyVsAG6oPDoABUkJpxMRaK5QIZWwUAEcvA1MFTCbSeTKCIjkZK1WTiJgCMsGKKpYCJeKgaECFsWExQiqtdz6RTIQj0SjZQqlVSxUCnaT9YbiMa0gAvTCoKgQBmc2kSjgLWicACsvD8HC0pFQnDc1msstOqwRZnRPFIBE0CYWAGsQOj0b9603my22fpOJI05Ws5xeAoQBpy5WFnBYEg0CwknRYuRKBOp/Q4sAFMwkgoEKgCKQsLy8KsAGp4TAAdwA8od02WaLQocR%2BxAot2oqEGntOGWJ2xBKeGLQ3xneCwW0jHEADtzwfUal5aFu0%2BaovChd9eCtTAkzA2g8CiYhXw8LBu1BPAWCQhYqAMZdDxPc9GCQmRBBEMR2CkWj5CUNRu10Lh9EMYw80sfRMP7SAFlQJJHAEfsOD7VDqjEvwIFcUY/E44IphKMo9BSNJZMUjT8lk3o1NmWxpI6BguhGTwWj0dpZPMyZin6cohm6HTOJBboDMciQFgUQtGMTFMuzA7MOC2VQAA42QAWjZSQtmAZBkC2aMwQYas5mS3BCAecxSzmXgKwAuYazrBsW3Kps2zQztSHTTMQr7AchyK0hR0QFBUEnacyAoCB526kBl1XddN23TBdwPI8zwvGjr1ve9HzA59mGIf8P06r8CB/P9uyA7jQMzfBIMcaCJMzODkAQtYyxQtDMwwrCcIwNZMwIojuATPgyIUCjpuoj7mPo8QmP4QRFBUdQwN0AIDCMFBeJsB7BKpLNRIyCSoqoBhUCi1DBUwKKmRxcEiDvKT7FklwGHcSycmU6nPJmJzNIKTJaaUvItIyRn1LckzbImVzjIp2oJh5oz3Is7IOcl%2Bzpl5ny/O89sOFTWruxCsLIpiuKEqSlKvDSjKICy0nizygrhxK%2BtGwq8qVZqureAa2wmsKrRipVswgvq3tmo9hZoLvDIQEkIA) Notice how the body of `main` is identical no matter if copy elision is enabled or not. To get `test` passed in a register you must remove the copy constructor. I spent a few hours being really confused by this note before I tracked down the original PR and realized what it was trying to talk about. Hopefully this saves the next person to come across it the same trouble. As an aside I suspect the clang c bindings can already give you information on special member functions and base classes, making it fairly easy to do this correctly. AFAICT bindgen already does not rely on llvm's code generation facilities to figure out the ABI of calls for C (except perhaps indirectly, via rustc), so this seems reasonable to just do in bindgen, explicitly. --- book/src/cpp.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/book/src/cpp.md b/book/src/cpp.md index 75ef855494..6928584627 100644 --- a/book/src/cpp.md +++ b/book/src/cpp.md @@ -72,7 +72,10 @@ cannot translate into Rust: [the tracking issue for exceptions](https://github.com/rust-lang/rust-bindgen/issues/1208) for more details. -* Return value optimization. C++ compilers will in certain circumstances optimize functions - returning a struct type value to instead take an extra hidden argument that refers - to the return value struct. `bindgen` cannot necessarily know about this optimization and - thus at present `bindgen`-interfaces for these kinds of functions are invalid. +* Many C++ specific aspects of calling conventions. For example in the Itanium abi types that are + "[non trivial for the purposes of calls](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#non-trivial)" + should be passed by pointer, even if they are otherwise eligable to be passed in a register. + Similarly in both the Itanium and MSVC ABIs such types are returned by "hidden parameter", much like + large structs in C that would not fit into a register. This also applies to types with any base classes + in the MSVC ABI (see [x64 calling convention](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values)). + Because bindgen does not know about these rules generated interfaces using such types are currently invalid.