-
Notifications
You must be signed in to change notification settings - Fork 1.6k
RFC for #[stable(since)]
#3854
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
RFC for #[stable(since)]
#3854
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
- Feature Name: stable_since | ||
- Start Date: 2025-09-12 | ||
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) | ||
- Rust Issue: [rust-lang/rust#74182](https://github.com/rust-lang/rust/issues/74182) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Allow crates to specify `#[stable(since = "version")]` on items for Rustdoc to render the information. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
This functionality is already implemented for the standard library. Other crates also expand their public API over time, and it would be helpful to inform users about the minimum crate version required for each item. | ||
|
||
It's possible to automatically infer in which version each item has been added by comparing public APIs of crates' public releases, but this is too expensive and complicated to perform each time when generating documentation. The `#[stable(since)]` attribute behaves like a first-class cache for this information for `rustdoc` and other tools. | ||
|
||
# Guide-level explanation | ||
[guide-level-explanation]: #guide-level-explanation | ||
|
||
When added to an item, it specifies in which version of the crate this item has been added: | ||
|
||
```rust | ||
#[stable(since = "2.25.0")] | ||
pub fn add_trombone_emoji() {} | ||
``` | ||
|
||
Rustdoc will include the version in the documentation of the item, with a description such as "stable since $crate_name version 2.25.0". | ||
|
||
To ease development of unreleased features, there is no restriction on the version range, and it may refer to a future not-yet-released version. | ||
|
||
# Reference-level explanation | ||
[reference-level-explanation]: #reference-level-explanation | ||
|
||
The `version` must parse as SemVer. It refers to a version of the crate that defines the item this attribute belongs to. | ||
|
||
`rustc` doesn't need to be made aware of crates' versions, because there's no restriction on the version range. | ||
|
||
`rustdoc` should not display the attribute on items re-exported from other crates. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
This attribute may be incorrect if added manually. It may be confused with rustc version compatibility. | ||
|
||
It specifies only a single version per item, which may not be enough to fully explain availability of items that are available conditionally or under different paths. | ||
|
||
Versions on re-exported items are not relevant for the crate re-exporting them, because it matters when the re-export has been added. | ||
|
||
# Rationale and alternatives | ||
[rationale-and-alternatives]: #rationale-and-alternatives | ||
|
||
- The entire `#[stable(feature)]`/`#[unstable(feature)]` functionality could be stabilized for 3rd party crates | ||
- API stability could be stored outside of the source code, e.g. in a file similar to `rustdoc`'s JSON | ||
- It could be shortened to `#[since("version")]` | ||
- It could be expanded to `#[stable(added = "version", changed = "version", rust_version = "msrv")]` | ||
kornelski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
# Prior art | ||
kornelski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[prior-art]: #prior-art | ||
|
||
The `#[stable(since = "version")]` attribute is a subset of standard library's `#[stable(feature, since)]`, but to keep the scope small, this RFC does not include support for feature flags nor unstable APIs outside of the standard library. | ||
|
||
# Unresolved questions | ||
[unresolved-questions]: #unresolved-questions | ||
|
||
Should crates reset the `version` when making semver-breaking changes to the item? | ||
|
||
Should the `version` allow a placeholder value like `UNRELEASED`? | ||
kornelski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
Is it clear enough that the version is the crate's own version and not the minimum requierd Rust version? | ||
kornelski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
How to support items re-exported from other crates? Could `use` support overriding `#[stable(since)]`? | ||
|
||
# Future possibilities | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Even better if we can get some form of "behavior change" and "remove attributes" (along with the stable |
||
[future-possibilities]: #future-possibilities | ||
|
||
The entire `#[stable(feature)]`/`#[unstable(feature)]` functionality could be stabilized for 3rd party crates. | ||
|
||
Tools like rust-analyzer or clippy could help users bump versions in `Cargo.toml` when their crate uses items from a newer version of a dependency than the minimum version specified in `Cargo.toml`. | ||
kornelski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
These attributes could be automatically generated by tools like `cargo-public-api` or `cargo-semver-checks`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be multiple ways something can be stable. Today,
std
also usesconst_stable
. I assume this should at least be acknowledged in case it can affect the design. Today they are separate attributes. Should we instead generalizestable
to make it work for both? What impact may that have on this attribute?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's best to start with the simplest possible case and worry about the full situation later. I have some notes and design sketches for my thoughts if you'd like to discuss it on Zulip.