Rust could do something like this but it would need syntactic support for something like “throw.” In this hypothetical world, on throw the compiler could generate code that does the unwinding and all that. When a normal value is returned, it would just return as normal. The function call ABI would be one such that functions that returned Result<T> and returned normally would be assumed to have succeeded. Actually Result<T> wouldn’t need to be a real type, just decoration at the syntax level.
They only execute instructions when they happen... but they still inhibit the optimizer when they don't. Calls that may throw act like branches in the control flow graph. They also introduce more code bloat for their landing pads.
> Rust’s model for errors is tied to a specific implementation.
The Rust ABI is unspecified for a reason. We're currently seeing a lot of optimization around struct and enum layout; I'm not sure why this couldn't be applied to the calling convention without any extra syntax for "throw."
This is a fair point and elucidates the trade off being made. Perhaps this is the reason C++11 has the “nothrow” attribute.
I bring this up because I don't believe the thing you're seeing is inherent to this style of error-handling, but instead to the language's support for these kinds of monadic patterns. Haskell would look even more succinct than the Rust!