On Windows, SEH (Structured Exception Handling) is used somewhat similarly to Unix signals, albeit they're not quite the same. Handling these exceptions is essential for some for some system APIs as well as RPC. It's also the basis for C++ exceptions (though they build alot on top of it).
In MSVC C/C++ there is the __try statement for this:
Rust has no equivalent, which necessitates writing C shims. Could there be a core::os::windows::{seh_try_except, seh_try_finally} or something like that?
They would probably have to be macros if they want to follow the C semantics exactly. E.g.:
seh_try_except! {
try: { ... }
filter: ... // must only be a one line statement, though can be a function call
except: { ... }
}
But if we mandate function calls (so not placed inline, unless some optimizers decides to) then it could be something that takes FnMut functions and callback to them.
Also why core and not std? This would be the first such core os API.
Because, similar to signals, it's a fundamental part of the platform. It's also not the first thing that depends on the OS, even if we abstract over it. E.g. SIMD or core::ffi can be dependent on the OS in different ways (if only due to differing types).
Signals are in std, not core, despite being a fundamental part of the Unix platforms. And core::ffi doesn't have things that are directly OS dependent (e.g. OsStr and OsString are only in std::ffi, not core::ffi).
The things that are in core::ffi are the things that are defined by a C compiler regardless of whether it's running on an OS or not, which seems like a reasonable dividing line - std for "needs an OS present to be meaningful", core for "exists in the absence of an OS") - and that dividing line would put SEH in std, not core.
Without having it in core, it make Rust useless for some cases that C can handle.
The difference with signals is that they can be done in a third party crate whereas SEH is compiler magic. This needs compiler support. And the rustc compiler (even in no_std) absolutely depends on the OS (at a minimum the binary format but a lot of other details too, and as you say, a C-like runtime).
Is there an argument here for another standard library crate, perhaps?
Currently, we have core, alloc, and std, where std is "everything", core is "stuff that's present in the absence of an OS", and alloc is "stuff that depends on a working heap allocator". You could add an seh crate (with associated compiler support) that's like alloc, but for SEH stuff instead of heap allocator stuff.
Then, where you need SEH, you can use both core and seh together, but that leaves the clear distinction of core as stuff that could be done without an OS (even though it depends on details of the OS).
The intrinsic is called catch_unwind nowadays, but the wrapper in std::panicking is still called r#try (link is to 2nd party stdlib docs that includes private items).
The specifics of how the catch_unwind intrinsic works is of course compiler-internal implementation detail, but you can look at the source of panic_unwind to see what handlers are defined there. Likely unfortunate for attempting to interact more directly with SEH, a decent portion of it is actually handled directly in LLVM in order to provide a more consistent unwinding and landing pad structure between Itanium EH and SEH while still making reasonably efficient utilization of the unwinding mechanism. (E.g. if I recall and understood the LLVM EH docs correctly (about 80% confidence) drop glue which does not terminate the unwinding actually fully runs within the SEH __except filter callback (returning EXCEPTION_CONTINUE_SEARCH) to avoid needing to terminate and reraise the exception every frame. This is why forced unwinds “work” on Windows but “don't work” on Linux (depending on what you consider “working” for a forced unwind).)
Due to how LLVM utilizes SEH, I don't think it's possible to directly match the semantics of SEH __try in an LLVM compiled language, and you must involve either some MSVC compiled objects or maybe can manage with some inline assembly.