# How to use #[unstable_feature_bound] ## Introduction Previously, if we have a stable type ``StableType`` and stable trait ``StableTrait``, ``impl StableTrait for StableType`` will be instantly stable, and there is no way to mark the impl as unstable. In [#140399](https://github.com/rust-lang/rust/pull/140399#issuecomment-3070894211), we started to provide a way to mark an impl as unstable through ``#[unstable_feature_bound(feature1, feature2,..)]``, for example: ```rust= #![stable(feature = "a", since = "1.1.1" )] #[stable(feature = "a", since = "1.1.1" )] pub trait Foo { #[stable(feature = "a", since = "1.1.1" )] fn foo(); } #[stable(feature = "a", since = "1.1.1" )] pub struct Bar; #[unstable_feature_bound(feat_bar)] #[unstable(feature = "feat_bar", issue = "none" )] impl Foo for Bar { fn foo() {} } ``` ## Usage ``#[unstable_feature_bound]`` should be used together with ``#[unstable]``. ```rust= #[unstable_feature_bound(feat_bar)] #[unstable(feature = "feat_bar", issue = "none" )] impl Foo for Bar { fn foo() {} } ``` Conceptually, ``#[unstable_feature_bound]`` is a where-clause, just like ```rust= impl Foo for Bar where unstable_feature_bound(feat_name) {} ``` If we are in std / core, ``#[unstable_feature_bound(feat_name)]`` is always required to use anything that is annotated with ``#[unstable_feature_bound(feat_name)]``. Outside of std/core, any item annonated with ``#[unstable_feature_bound(feat_name)]`` in std / core will be treated like a normal unstable feature. Users just need to enable the feature through ``#![feature(feat_name)]`` to use the item. **Usage example in std / core:** ```rust= #![stable(feature = "a", since = "1.1.1" )] #[stable(feature = "a", since = "1.1.1" )] pub trait Foo { #[stable(feature = "a", since = "1.1.1" )] fn foo(); } #[stable(feature = "a", since = "1.1.1" )] pub struct Bar; // If this impl is annotated with #[unstable_feature_bound(feat_bar)]... #[unstable_feature_bound(feat_bar)] #[unstable(feature = "feat_bar", issue = "none" )] impl Foo for Bar { fn foo() {} } // Then the same #[unstable_feature_bound(feat_bar)] is needed // to use anything annonated with #[unstable_feature_bound(feat_bar)]. #[unstable_feature_bound(feat_bar)] #[unstable(feature = "feat_bar", issue = "none" )] fn bar() { Bar::foo(); } // The same rule also applies to `bar2`, since it uses `bar`. #[unstable_feature_bound(feat_bar)] #[unstable(feature = "feat_bar", issue = "none" )] fn bar2() { bar(); } ``` **Usage example outside of std / core**: ```rust= // If we have the code below in std / core... // ----- std / core ---------------------------------------- #![stable(feature = "a", since = "1.1.1" )] #[stable(feature = "a", since = "1.1.1" )] pub trait Foo { #[stable(feature = "a", since = "1.1.1" )] fn foo(); } #[stable(feature = "a", since = "1.1.1" )] pub struct Bar; // If this impl is annotated with #[unstable_feature_bound(feat_bar)]... #[unstable_feature_bound(feat_bar)] #[unstable(feature = "feat_bar", issue = "none" )] impl Foo for Bar { fn foo() {} } // ----- std / core ---------------------------------------- //----- Outside of std / core ---------------------------- // Then the feature `feat_bar` should be enabled to use the impl. #![feature(feat_bar)] use std::{Foo, Bar} fn main() { Bar::foo(); } //----- Outside of std / core ---------------------------- ``` ## Limitation We do not support: - Using ``#[unstable_feature_bound]`` within stable API. Once ``#[unstable_feature_bound]`` is used on an item, user will be required to enable the feature through ``#[feature]``, so using ``#[unstable_feature_bound]`` within stable API will essentially make the item unstable. - Using ``#[unstable_feature_bound]`` on any item other than impls and free functions. We plan to remove these limitations eventually. ## Some examples that are not allowed ```rust= #[unstable_feature_bound(feat_bar)] #[unstable(feature = "feat_foo", issue = "none" )] impl Foo for Bar { fn foo() {} } ``` - the feature name in ``#[unstable]`` is not in ``#[unstable_feature_bound]``. In this case, the user is required to enable the feature through ``#![unstable(feat_bar)]`` instead of ``#![feature(feat_foo)]``. ```rust= #![stable(feature = "a", since = "1.1.1" )] #[stable(feature = "a", since = "1.1.1")] #[unstable_feature_bound(feat_bar)] fn bar() {} ``` - If an item is annotated with ``#[unstable_feature_bound]``, the user will be required to enable the feature through ``#![feature]``. So the item is essentially no longer stable. The examples above will fail with error. If you think there are more cases that are confusing / should not be allowed, feel free to ping @tiif on github / zulip.