At a minimum, writing a no_std application requires start and several lang items; commonly, users of no_std may also want no_main, and an intrinsic like intrinsics::abort().
I would guess that everything on that list other than the lang items is ready for stabilization already; I canât think of any obvious issues, though Iâd welcome any suggestions on that point.
As for the lang items required: what might block stabilization of those? What might it take to bring them to a stable state? Does anyone have planned changes they want to make to them?
I imagine some of this stuff will be de-facto stabilized and we can sorta just give in and say âyeah, itâs stable nowâ. The more years that go by the harder it will be to tweak these things.
The exception handling stuff is pretty frightening to stabilize since that is directly tied to whatever LLVM is doing this year.
I imagine @japaric has some opinions about this subject.
Mm Iâd like to write a proposal for âneeds providesâ which among other things would replace a lot of start/main/entry point stuff and panicking language items, among other things. Therefore Iâm not too excited to them stabilized now.
First of all, the only unstable feature really required to build a no_std
application is the panic_fmt lang item. See reworked no-stdlib example from
the book:
Second, the no-stdlib example in the book is not a good representation of
no_std applications, IME. It says that no_std is meant to be used on systems
where âthreads, networking, heap allocation, and othersâ may not be available,
but then tells you to use the libc crate / C library, which is a library
mainly used to interface the OS to get access to threads, networking, heap
allocation and others. A usual embedded / bare metal Rust application doesnât
link to the C library; of course, you are free to do so if you want to provide
some sort of POSIX layer or etc.
Finally, on some embedded / bare metal applications the panic_fmt
requirement is totally artificial. Itâs usually the case that youâll build your
program so that it never panics (as panics on a system where thereâs no panic
recovery can be as bad as memory corruption) so your final binary, when
compiled in release mode, is free from calls to rust_begin_unwind (what the
panic_fmt lang item maps to). I personally would like to see official support
for this scenario: maybe some -C panic=undefined mode where the compiler does
not demand the panic_fmt lang item and instead just leaves the
rust_begin_unwind symbol undefined; the linker would then either complain at
link time if your program does contain panics or your link program correctly if
it doesnât have any. This undefined mode seems even easier to stabilize than
the panic_fmt lang item as we donât have to decide on any function signature.
I admit that I have little to no experience with embedded programming, but I struggle to imagine a non-trivial program where this works at all, let alone is a sustainable strategy. Any array subscript operation, any unwrap, and assertions in a number of core APIs will necessarily introduce the possibility of panics. It's true that these can often be optimized out, but if you bank on that, whether your program can be built depends on the optimizer's whims, which can notoriously vary depending on the phase of the moon and the exact way you write your program. Furthermore, from how often we get bug reports about bounds checks not being elided in obvious cases, I doubt that even programs that obviously don't panic (as opposed to not panicking because of subtle global invariants) can be linked successfully in this mode.
Only if we decide we don't care that someone's program will stop linking every time we change anything at all about code generation (MIR building, MIR optimizations, the entirety of trans, and the LLVM version). That seems like a radical departure from what we usually mean by "stabilizing" something.
What does it mean to have a stable feature which canât be compiled using a stable compiler? (A library using #[no_std] can be compiled on stable, but not a standalone executable.)
Canât #[panic_fmt] just be ignored if it doesnât exist? Whatâs the worst that could happen? I suppose this would be implemented as an infinite loop, since it has to be ! anyways. Granted, this results in a really bad experience if you do panic, but it would allow people to develop on nightly using unstable features for debugging while shipping something from stable which âprobablyâ doesnât panic.
What would be really nice here are some default strategies for #[panic_fmt] which could be easily stabilized.
You could imagine something like:
#[lang_default(panic_fmt, loop)]
âŚwhich goes into an infinite loop. Or if you got the abort intrinsic working:
#[lang_default(panic_fmt, abort)]
One of the no_std environments I work in has a minimalist pseudo-libc that supports a few things like printf(), abort(), etc (although little else). Perhaps you could even have:
I like the lang default idea, Iâve been considering writing an RFC for something like this before.
One nit: It should probably not share names with lang items (those names will always be an implementation detail), but instead it should have some new name like #[use_lang_default(panic_strategy, loop)] or something. This way it can also cover multiple lang items if necessary.
It works for me on rustc 1.20.0-nightly (15aa15b03 2017-07-21). If you post your code I can take a look in case it's something simple. I used [profile.dev] panic = "abort".