Recently I've been overhauling the mechanisms for introducing unstable features to both the Rust language and libraries. Part of that work landed for the 1.0.0-alpha release when we started producing warnings about using unstable library APIs, which I'm sure you noticed. Now the transition to the system described in RFC 507 is nearing completion, so it's time to remind everybody what's happening and how to cope with it.
We want to evolve the Rust process such that new features progress into the language in a controlled and predictable way, so that there are yet fewer suprizes about what is or isn't ready for use, and risk of new features becoming de-facto stable through early adoption is minimized. From now on every feature going into either the Rust language or the standard library is identified by a feature name, extending the feature-gating mechanism used by the language to the standard library.
For the remainder of the current development cycle, the nightly compiler will print a warning for all code that uses unstable features:
/home/brian/test.rs:1:22: 1:44 warning: use of unstable library feature 'core'
/home/brian/test.rs:1 fn main() { unsafe { std::intrinsics::abort() } }
^~~~~~~~~~~~~~~~~~~~~~
/home/brian/test.rs:1:22: 1:44 help: add #![feature(core)] to the crate attributes to silence this warning
/home/brian/test.rs:1 fn main() { unsafe { std::intrinsics::abort() } }
^~~~~~~~~~~~~~~~~~~~~~
During the first 1.0 beta cycle these will be converted to errors on the nightly channel, and authors will be required to explicitly opt-in to use of unstable libraries to keep their code compiling. On the beta and stable channels it will not be possible to use unstable features. We hope that between upstream stabilization and feedback from downstream authors we will converge upon a clearly-defined subset of the Rust libraries that are stable and that can support a substantial collection of the crates in the Cargo registry.
Taking Rust from its historical posture in which unstable features are always available to one in which only stable features are available in production releases is a big and painful change to work through. As a crate author here's what you need to know:
To use unstable features you must always declare so by putting
#![feature(foo)]
at the top of your crate. While this has been true
for language features for a long time, it is now true for the standard
library as well. You are going to be doing a lot more of this in the
short term until std stability for 1.0 has completely shaken out -
hang in there!
Once the betas start and using unstable features without opting in
becomes an error (wheras now it's a warning), it will be trivial to
determine whether your code is using the stable - and backwards
compatible - subset of the language: any Rust crate that contains no
#![feature]
attributes is written in a stable dialect of Rust.
As introduced, the current unstable library features are rather-coarse-grained. Some of those likely to impact existing code include:
io
- All ofstd::io
os
- All ofstd::os
path
- All ofstd::path
hash
- All ofstd::hash
collections
- Thecollections
crate and collections reexported fromstd
rand
- Therand
crate and its componentsn reexported fromstd
core
- Everything else that's unstable incore
std_misc
- Everything else that's unstable instd
test
- Thetest
craterustc_private
- In-tree components that only the compiler should be using
During their unstable development feature names may change incompatibly, and in particular be divided into smaller subsets with different unique feature names. You are likely to see more features appear in the coming weeks as the remaining unstable APIs are scrutinized.
If this seems painful try to be reassured that we dearly want your crates to work on the stable release channel and will do everything we can to make that happen as fast as reasonably possible. In the coming weeks there will be a concerted effort to lift as much of the cargo ecosystem onto the stable subset of the language as possible.
Deprecation continues to work the same as it always has, via the
'deprecated' lint, so deprecated APIs can be opted into with
#[allow(deprecated)]
.
For people hacking on rust itself there are a number of things to know. Firstly, the in-tree design is not intended to make your life easier - lots of stuff has to be tagged with metadata, but only incrementally more so than before.
Crates that participate in feature staging (i.e. every crate in-tree
and no others) need to opt in. This requires the #[staged_api]
attribute, which itself requires the staged_api
feature. Being
'staged_api' is what tells rustc it needs to interpret the 'unstable',
'stable', and 'deprecated' attributes (while leaving the possibility
of also using those names for non-staged-api purposes later).
Therefore every crate in-tree must say:
#![feature(staged_api)]
#![staged_api]
Nearly every crate that is not part of the standard facade should
additionally include the crate header #![unstable(feature = "rustc_private")]
, which says 'this crate is not for public
consumption'.
When adding a new public API to the standard library or to a crate in the standard facade, you need to tag it unstable and give it a feature name:
#[unstable(feature = "new_hotness")]
fn new_hotness() { }
Increasingly, this feature name should come out of the RFC process, and adding APIs without knowing what feature it is part of will be an indication that the development process is not proceeding in order.
Unstable features inherit so lexically, so you often only need a single one.
When a feature becomes stable you change the attribute from 'unstable' to 'stable' and add the 'since' attribute:
#[stable(feature = "new_hotness", since = "1.1.0")]
fn new_hotness() { }
'since' is the version in which that feature will hit the stable
release channel and at the time of promotion should be equal to the
value CFG_RELEASE_NUM
in main.mk
.
The stable
attribute does not inherit lexically, so most items need
to be tagged explicitly, including trait methods and inherent methods.
No single feature can be both unstable and stable, so if only part of an unstable feature needs to be promoted then it must be split into two features. All the 'since' attributes must agree for a given feature. A new tidy script enforces both these and can be run with 'make tidy-features'.
Deprecating an API can be done with #[deprecated(since = "1.1.0")]
,
the same as before, but now requiring 'since'. Since both unstable and
stable libraries can be deprecated, all deprecated attributes must be
paired with either 'unstable' or 'stable'.