- Feature Name:
- Start Date: 2018-06-14
- RFC PR: rust-lang/rfcs#2480
- Rust Issue: rust-lang/rust#27783
This crate provides the subset of the standard library’s functionality that requires
a global allocator (unlike the
core crate) and an allocation error handler,
but not other operating system capabilities (unlike the
In some environments the
std crate is not available:
micro-controllers that don’t have an operating system at all, kernel-space code, etc.
#![no_std] attribute allows a crate to not link to
core instead with only the subset of functionality that doesn’t have a runtime dependency.
core crate does not assume even the presence of heap memory,
and so it excludes standard library types like
However some environments do have a heap memory allocator
free C functions),
even if they don’t have files or threads
or something that could be called an operating system or kernel.
Or one could be defined in a Rust library
ultimately backed by fixed-size static byte array.
An intermediate subset of the standard library smaller than “all of
but larger than “only
core” can serve such environments.
In 2018 there is a coordinated push
no_std application compatible with Stable Rust.
As of this writing not all of that work is completed yet.
#[panic_implementation] is required for
no_std but still unstable.
So it may seem that this RFC does not unlock anything new,
no_std application still need to be on Nightly anyway.
The immediate impact can be found in the library ecosystem.
Many general-purpose libraries today are compatible with Stable Rust
and also have potential users who ask for them to be compatible with
For a library that is fundamentally about using for example TCP sockets or threads, this may not be possible.
For a library that happens to only use parts of
std that are also in
(and are willing to commit to keep doing so), this is relatively easy:
#![no_std] to the crate, and change
std:: in paths to
And here again, there is the intermediate case of a library that needs
or something else that involves heap memory, but not other parts of
std that are not in
Today, in order to not lose compatibility with Stable,
such a library needs to make compatibility with
no_std an opt-in feature flag:
#![no_std] #[cfg(feature = "no_std")] extern crate alloc; #[cfg(not(feature = "no_std"))] extern crate std as alloc; use alloc::vec::Vec;
But publishing a library that uses unstable features, even optionally, comes with the expectation that it will be promptly updated whenever those features change. Some maintainers are not willing to commit to this.
With this RFC, the library’s code can be simplified to:
#![no_std] extern crate alloc; use alloc::vec::Vec;
… and perhaps more importantly, maintainers can rely on the stability promise made by the Rust project.
#![no_std] in a crate, that crate does not implicitly depend on
but depends on
core instead. For example:
-use std::cell::RefCell; +use core::cell::RefCell;
APIs that require a memory allocator are not available in
In order to use them,
no_std Rust code must explicitly depend on the
#[macro_use] extern crate alloc; use core::cell::RefCell; use alloc::rc::Rc;
core, this dependency does not need to be declared in
alloc is part of the standard library and distributed with Rust.
The implicit prelude (set of items that are automatically in scope) for
does not assume the presence of the
alloc crate, unlike the default prelude.
So such crates may need to import either that prelude or specific items explicitly.
use alloc::prelude::*; // Or use alloc::string::ToString; use alloc::vec::Vec;
[¹] … and other roots of a dependency graph, such as
alloc crate makes two additional requirements:
A global heap memory allocator.
An allocation error handler (that is not allowed to return). This is called for example by
Vec::push, whose own API is infallible, when the allocator fails to allocate memory.
std provides both of these. So as long as it is present in the dependency graph,
nothing else is required even if some crates of the graph use
std is not present they need to be defined explicitly,
somewhere in the dependency graph (not necessarily in the root crate).
#[global_allocator]attribute, on a
staticitem of a type that implements the
GlobalAlloctrait, defines the global allocator. It is stable in Rust 1.28.
Tracking issue #51540 propose the
#[alloc_error_handler]attribute for a function with signature
fn foo(_: Layout) -> !. As of this writing this attribute is implemented but unstable.
alloc crate already exists (marked unstable),
and every public API in it is already available in
Except for the
alloc::prelude module, since PR #51569 the module structure is a subset
of that of
std: every path that starts with
alloc:: is still valid and point to the same item
after replacing that prefix with
std:: (assuming both crates are available).
The concrete changes proposed by this RFC are:
extern crate alloc;(that is, change
#![stable]near the top of
alloc::preludemodule and its contents (which is only re-exports of items that are themselves already stable).
Stabilize the fact that the crate makes no more and no less than the two requirements/assumptions of a global allocator and an allocation error handler being provided for it, as described above.
The exact mechanism for providing the allocation error handler is not stabilized by this RFC.
In particular, this RFC proposes that the presence of a source of randomness is not a requirement that the
alloccrate can make. This is contrary to what PR #51846 proposed, and means that
std::collections::hash_map::RandomStatecannot be moved into
Tracking issue #27783 tracks “the
crates whose contents are re-exported in
std but also exist separately.
Other such crates have already been moved, merged, or stabilized,
alloc is the only remaining unstable one.
Therefore #27783 can serve as the tracking issue for this RFC
and can be closed once it is implemented.
The structure of the standard library is therefore:
core: has (almost) no runtime dependency, every Rust crate is expected to depend on this.
alloc: requires a global memory allocator, either specified through the
#[global_allocator]attribute or provided by the
std: re-exports the contents of
allocso that non-
no_stdcrate do not need care about what’s in what crate between these three. Depends on various operating system features such as files, threads, etc.
proc-macro: depends on parts of the compiler, typically only used at build-time (in procedural macro crates or Cargo build scripts).
Tracking issue #27783 is the tracking issue for the
alloc crate and, historically, some other crates.
Although I could not find much discussion of that, I believe it has been kept unstable so far
because of uncertainty of what the eventual desired crate structure
for the standard library is, given infinite time and resources.
In particular, should we have a single crate with some mechanism for selectively disabling
or enabling some of the crate’s components, depending on which runtime dependencies
are available in targeted environments?
In that world, the
no_std attribute and standard library crates other than
would be unnecessary.
By stabilizing the
alloc crate, we commit to having it − and its public API − exist “forever”.
core and the
no_std attribute are already stable,
so in a sense it’s already too late for the “pure” version of the vision described above
std really is the only standard library crate that exists.
It may still be desirable to regroup the standard library into one crate,
and it is probably still possible.
core crate could be replaced with a set of
pub use reexport
to maintain compatibility with existing users.
Whatever the eventual status for
we can do the same for
PR #51569 mentioned above also hopes to make this easier.
While we want to leave the possibility open for it,
at the time of this writing there are no concrete plans
for implementing such a standard library crates unification any time soon.
So the only alternative to this RFC seems to be
leaving heap allocation for
no_std in unstable limbo for the foreseeable future.
PR #51569 proposed adding a source of randomness to the other requirements
made by the
This would allow moving
HashMap (which has
RandomState as a default type parameter),
This RFC chooses not to do this because it would make it difficult to use for example
in environments where a source of randomness is not easily available.
I hope that the language will eventually make it possible to have
without a default hasher type parameter, and have the same type in
std with its current default.
Although I am not necessarily in favor
of continuing the increase of the number of crates in the standard library,
another solution for
no_std might be another intermediate crate
that depends on
alloc and adds the randomness source requirement.
Additionally, with this RFC it should be possible to make https://crates.io/crates/hashmap_core
compatible with Stable Rust.
The downside of that crate is that although based on a copy of the same code,
it is a different type incompatible in the type system with
I am not aware of a mechanism similar to
no_std in another programming language.
Newlib is a C library for “embedded” systems that typically don’t have an operating system.
It does provide a memory allocator through
malloc and related functions, unconditionally.
Did I miss something in PR #51569 that makes
allocnot a subset of
std? A double-check from someone else would be appreciated.
Should the crate be renamed before stabilization? It doesn’t have exclusivity for memory-allocation-related APIs, since the
core::allocmodule exists. What really characterizes it is the assumption that a global allocator is available. The name
global_allocwas proposed. (Although the crate doesn’t only contain the global allocator itself.)
alloc::preludemodule be moved to
alloc::prelude::v1? This would make the
allocmodule structure a subset of
stdwithout exception. However, since this prelude is not inserted automatically, it is less likely that we’ll ever have a second version of it. In that sense it is closer to
std::prelude::v1.~ Done in PR #58933.
In addition to being a subset of
std, should the
alloccrate (by itself) be a super-set of
core? That is, should it reexport everything that is defined in
core? See PR #58175 which proposes reexporting