Rust doesn't have exceptions in the sense that C++/Java/Python/etc. have exceptions, i.e., things that unwind the stack and are part of a function's expected API. And I think the specific reason they're out of style is the inherent contradiction in that statement: either all the exceptions in the API of any of the functions you call are also part of your public API, or you're carefully filtering exceptions in any of the functions you call that raise them, and so you might as well not use unwinding.
Panics unwind the stack, but are not part of the API; they're for erroneous conditions where the usual right thing to do is to kill the process, but maybe you only want to kill e.g. the current HTTP request. Errors as return values / the Result<T, E> type do not automatically unwind - they're just normal data types returned from a function - but they have syntax (the question mark operator) for explicitly unwinding them one step, and there are proposals in progress to introduce syntax that use "throw" or "catch" to refer to returning the error case or handling such returns in a block of code, so it seems like people think Result more closely matches exceptions in other languages.
I don't really see a huge distinction between a language and its community, for the primary reason that feature evolution in a language - e.g., that Results recently got the question-mark operator, and whether Results will get "throw"/"catch" syntax - is driven by the language community and what sorts of things are or aren't common practice. A Rust community that made heavy use of panics in normally-operating code would probably want to fork Rust just to optimize panicking and catching panics, to fix the fact that catch_unwind is documented to not necessarily catch all panics, etc., and would eventually make deeper language changes to improve the syntax around doing panicking and not merge the corresponding changes to improve the syntax around Result. Which is historically what's happened with languages that have developed multiple communities - there are lots of Lisp dialects, lots of BASIC dialects, etc. Whether BASIC has a feature isn't a well-formed question; whether GW-BASIC or VB.NET or your TI-83 has a feature is well-formed.
We've long since past the time that we have to worry about such concerns. "Exceptions for exceptional errors" just means that you have to write code that both cares about exception safety and propagates error codes from subroutines. It's the worst of both worlds.
Just use exceptions for all errors. It's elegant.
Java has a particularly inelegant and ugly solution here involving declaring what types of exceptions might be thrown. But that still doesn't change the fact that changing that list is an API change, it just makes it more explicit.
So if you care about API stability (and I firmly believe that no solution that ignores API stability is "elegant" - it is at best "cute"), you're basically required to catch the vast majority of exceptions your own dependencies generate and translate them to your own exception types. You'll need to make a MyHTTPLibCertificateValidationError, unwrap the contents of OpenSSLValidationError, and put them in the new object, or you can never switch away from OpenSSL without an API break. And you want your dependencies to follow the same discipline.
At that point, as I said above, why use unwinding? None of the exceptions in your program can safely pass more than one level of the call stack at a time; each level has to explicitly approve raising it another level or wrap the exception in its own type (or handle it). The only ones that can really unwind are standard library ones like OutOfMemoryError that are expected to go all the way up the call stack to the top of the program or at best the top of the current request, print or otherwise log a backtrace, and abort the entire thing in progress - i.e., exceptional conditions. Exceptions for expected conditions are a different thing entirely, precisely because you don't want unwinding, you want step-by-step propagation.
This has nothing to do with efficiency. This has to do with correctness and robustness.
And you get your syntactic elegance with a library for translating and wrapping error objects, like https://docs.rs/error-chain , combined with syntax for immediately translating and returning errors from dependencies, like https://doc.rust-lang.org/book/second-edition/ch09-02-recove... .
Some compilers even won't let you use them without turning on full-blown RTTI(or doing it implicitly for you) which is even worse.