I meant finally blocks... freeing memory, reverting changes, etc... which are things you'd use destructors for (and hence why you can't use setjmp/longjmp with them). If you don't do them then you mess up your program's state and hence have no way to ensure correct behavior afterward. This is why I mentioned
arbitrary callers: you have no idea what callers have done or what they still need to do before returning. Heck, even sort() could have allocated memory that you'd be leaking, and not all destructors are constrained to resource leaks either.
I don't know what you consider "exceptions proper" (do you have to inherit from Exception? do you even have to pass along extra information?) but I don't think I agree. My point is actually precisely that what you want is not a non-local jump, but actual unwinding. Semantically, this is what exceptions are: synchronous dynamic unwinding. If you have a way to stop control flow and unwind arbitrary callers in a synchronous manner, what you have is exceptions, regardless of the particular syntax or other details. (e.g., it's beside my point you can "throw" extra information alongside this mechanism, or whether it's part of the language or a library, or whether you do the unwinding on the heap vs. the stack, or whether it's functional or procedural, or what have you.)
And my overall point is that this kind of dynamic unwinding is necessary for you to be able to do certain things like canceling routines in the middle in a safe and well-defined manner. (Especially that Result<>/Optional<>/whatever explicit localized mechanism is in fashion these days is clearly an insufficient replacement for exceptions.)