7.3 KiB
Stability attributes
This section is about the stability attributes and schemes that allow stable APIs to use unstable APIs internally in the rustc standard library.
For instructions on stabilizing a language feature see Stabilizing Features.
unstable
The #[unstable(feature = "foo", issue = "1234", reason = "lorem ipsum")]
attribute explicitly marks an item as unstable. Items that are marked as
"unstable" cannot be used without a corresponding #![feature] attribute on
the crate, even on a nightly compiler. This restriction only applies across
crate boundaries, unstable items may be used within the crate that defines
them.
The issue field specifies the associated GitHub issue number. This field is
required and all unstable features should have an associated tracking issue. In
rare cases where there is no sensible value issue = "none" is used.
The unstable attribute infects all sub-items, where the attribute doesn't
have to be reapplied. So if you apply this to a module, all items in the module
will be unstable.
You can make specific sub-items stable by using the #[stable] attribute on
them. The stability scheme works similarly to how pub works. You can have
public functions of nonpublic modules and you can have stable functions in
unstable modules or vice versa.
Note, however, that due to a rustc bug, stable items inside unstable modules
are available to stable code in that location! So, for example, stable code
can import core::intrinsics::transmute even though intrinsics is an
unstable module. Thus, this kind of nesting should be avoided when possible.
The unstable attribute may also have the soft value, which makes it a
future-incompatible deny-by-default lint instead of a hard error. This is used
by the bench attribute which was accidentally accepted in the past. This
prevents breaking dependencies by leveraging Cargo's lint capping.
stable
The #[stable(feature = "foo", since = "1.420.69")] attribute explicitly
marks an item as stabilized. Note that stable functions may use unstable things in their body.
rustc_const_unstable
The #[rustc_const_unstable(feature = "foo", issue = "1234", reason = "lorem ipsum")]
has the same interface as the unstable attribute. It is used to mark
const fn as having their constness be unstable. This allows you to make a
function stable without stabilizing its constness or even just marking an existing
stable function as const fn without instantly stabilizing the const fnness.
Furthermore this attribute is needed to mark an intrinsic as const fn, because
there's no way to add const to functions in extern blocks for now.
rustc_const_stable
The #[rustc_const_stable(feature = "foo", since = "1.420.69")] attribute explicitly marks
a const fn as having its constness be stable. This attribute can make sense
even on an unstable function, if that function is called from another
rustc_const_stable function.
Furthermore this attribute is needed to mark an intrinsic as callable from
rustc_const_stable functions.
Stabilizing a library feature
To stabilize a feature, follow these steps:
- Ask a @T-libs-api member to start an FCP on the tracking issue and wait for
the FCP to complete (with
disposition-merge). - Change
#[unstable(...)]to#[stable(since = "version")].versionshould be the current nightly, i.e. stable+2. You can see which version is the current nightly on Forge. - Remove
#![feature(...)]from any test or doc-test for this API. If the feature is used in the compiler or tools, remove it from there as well. - If applicable, change
#[rustc_const_unstable(...)]to#[rustc_const_stable(since = "version")]. - Open a PR against
rust-lang/rust.- Add the appropriate labels:
@rustbot modify labels: +T-libs-api. - Link to the tracking issue and say "Closes #XXXXX".
- Add the appropriate labels:
You can see an example of stabilizing a feature with tracking issue #81656 with FCP and the associated implementation PR #84642.
allow_internal_unstable
Macros and compiler desugarings expose their bodies to the call
site. To work around not being able to use unstable things in the standard
library's macros, there's the #[allow_internal_unstable(feature1, feature2)]
attribute that allows the given features to be used in stable macros.
rustc_allow_const_fn_unstable
const fn, while not directly exposing their body to the world, are going to get
evaluated at compile time in stable crates. If their body does something const-unstable,
that could lock us into certain features indefinitely by accident. Thus no unstable const
features are allowed inside stable const fn.
However, sometimes we do know that a feature will get
stabilized, just not when, or there is a stable (but e.g. runtime-slow) workaround, so we
could always fall back to some stable version if we scrapped the unstable feature.
In those cases, the rustc_allow_const_fn_unstable attribute can be used to allow some
unstable features in the body of a stable const fn.
You also need to take care to uphold the const fn invariant that calling it at runtime and
compile-time needs to behave the same (see also this blog post). This means that you
may not create a const fn that e.g. transmutes a memory address to an integer,
because the addresses of things are nondeterministic and often unknown at
compile-time.
Always ping @rust-lang/wg-const-eval if you are adding more
rustc_allow_const_fn_unstable attributes to any const fn.
staged_api
Any crate that uses the stable, unstable, or rustc_deprecated attributes
must include the #![feature(staged_api)] attribute on the crate.
rustc_deprecated
The deprecation system shares the same infrastructure as the stable/unstable
attributes. The rustc_deprecated attribute is similar to the deprecated
attribute. It was previously called deprecated, but was split off when
deprecated was stabilized. The deprecated attribute cannot be used in a
staged_api crate, rustc_deprecated must be used instead. The deprecated
item must also have a stable or unstable attribute.
rustc_deprecated has the following form:
#[rustc_deprecated(
since = "1.38.0",
reason = "explanation for deprecation",
suggestion = "other_function"
)]
The suggestion field is optional. If given, it should be a string that can be
used as a machine-applicable suggestion to correct the warning. This is
typically used when the identifier is renamed, but no other significant changes
are necessary.
Another difference from the deprecated attribute is that the since field is
actually checked against the current version of rustc. If since is in a
future version, then the deprecated_in_future lint is triggered which is
default allow, but most of the standard library raises it to a warning with
#![warn(deprecated_in_future)].