MSVC has a warning C4532 for jumping out of a finally block. However, that only specifically covers "break", "continue", and "goto". There's no warning for "__leave" and "return".
It's not completely clear to me why MSVC considers "__leave" and "return" special, compared to other sorts of control flow. My best guess is that return-in-finally is so pervasive across drivers that the warning would be way too noisy. An alternative theory is that MSVC generates a call to _local_unwind in the normal path for certain uses of break/continue/goto, and that's somehow a hazard for unwinding.
In any case, the end result is that "return" shows up somewhat frequently in __finally blocks in Windows drivers, but I haven't seen any of the others.
This patch generates code that's similar to what MSVC generates: it branches directly to the return block for normal code, and uses _local_unwind to break out of exception handling.
Currently, this only handles "return". Adding support for other ways of exiting a __finally blocks should be straightforward on top of this; it's mostly a question of managing the different possible destinations.
To represent the _local_unwind, this patch includes a new intrinsic llvm.seh_localunwind. This generates the necessary arguments to _local_unwind to the nearest catchpad automatically.
Some basic testing shows this seems to do the right thing in simple cases.
Handling try/finally inside the try of a try/__finally depends on the change to WinException.cpp. Still a bit ugly, but not sure how to make it cleaner.
__try/__finally inside a __finally block is broken because recoverAddrOfEscapedLocal can't recover the address of a variable allocated inside a __finally block. (Here specifically, we compute the wrong value for SEHRetNowParent, but it's a general issue affecting any variable declared inside a __finally block.) We probably need to store the frame pointer in an alloca in the parent function, and then load it later so we can recover the pointer we want, or something like that.
Based on the patch by Ten Tzen, particularly the code to call _local_unwind. I rewrote a bunch of the code to simplify it, and avoid using _local_unwind in cases where it isn't necessary.