From fae83634754bd3f820c169f0eb713c8d16c34b2c Mon Sep 17 00:00:00 2001 From: AudaciousAxiom <179637270+AudaciousAxiom@users.noreply.github.com> Date: Fri, 4 Sep 2026 19:31:29 +0200 Subject: [PATCH 1/3] test(manifest): test the yet-unsupported feature documentation key --- tests/testsuite/features.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/testsuite/features.rs b/tests/testsuite/features.rs index ee57f1260ce..fd8628d19d5 100644 --- a/tests/testsuite/features.rs +++ b/tests/testsuite/features.rs @@ -2681,3 +2681,34 @@ c = [ [("Cargo.toml", normalized_manifest)], ); } + +#[cargo_test] +fn feature_has_documentation() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["feature-metadata"] + + [package] + name = "foo" + edition = "2015" + + [features] + foo = { enables = [], doc = "Enables foo." } + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .masquerade_as_nightly_cargo(&["feature-metadata"]) + .with_stderr_data(str![[r#" +[WARNING] Cargo.toml: unused manifest key: `features.foo.doc` +[WARNING] `foo` (manifest) generated 1 warning +[CHECKING] foo v0.0.0 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); +} From 9199a6eb8534154e0f5c872aae2a637f1d61906d Mon Sep 17 00:00:00 2001 From: AudaciousAxiom <179637270+AudaciousAxiom@users.noreply.github.com> Date: Fri, 4 Sep 2026 19:31:29 +0200 Subject: [PATCH 2/3] feat(manifest): support `feature-documentation` in manifests --- .../cargo-util-schemas/manifest.schema.json | 7 ++++ crates/cargo-util-schemas/src/manifest/mod.rs | 3 ++ doc/book/src/reference/unstable.md | 20 +++++++++++ tests/testsuite/features.rs | 35 +++++++++++++++++-- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/crates/cargo-util-schemas/manifest.schema.json b/crates/cargo-util-schemas/manifest.schema.json index 60eb5434b76..664fc48aa1e 100644 --- a/crates/cargo-util-schemas/manifest.schema.json +++ b/crates/cargo-util-schemas/manifest.schema.json @@ -649,6 +649,13 @@ "items": { "type": "string" } + }, + "doc": { + "description": "Documentation for the feature.", + "type": [ + "string", + "null" + ] } }, "required": [ diff --git a/crates/cargo-util-schemas/src/manifest/mod.rs b/crates/cargo-util-schemas/src/manifest/mod.rs index a51ac3ef7fc..1ca28b70e73 100644 --- a/crates/cargo-util-schemas/src/manifest/mod.rs +++ b/crates/cargo-util-schemas/src/manifest/mod.rs @@ -1520,6 +1520,9 @@ pub struct FeatureMetadata { /// Features that this feature enables. pub enables: Vec, + /// Documentation for the feature. + pub doc: Option, + /// This is here to provide a way to see the "unused manifest keys" when deserializing #[serde(skip_serializing)] #[serde(flatten)] diff --git a/doc/book/src/reference/unstable.md b/doc/book/src/reference/unstable.md index e9989e951d7..6a36842ce50 100644 --- a/doc/book/src/reference/unstable.md +++ b/doc/book/src/reference/unstable.md @@ -2396,6 +2396,26 @@ foo = { enables = [] } This is equivalent to the array-of-strings syntax. Support for other keys should be added later. +### feature-documentation + +* Tracking Issue: [#17445](https://github.com/rust-lang/cargo/issues/17445) +* RFC: [#3485](https://github.com/rust-lang/rfcs/blob/master/text/3485-feature-documentation.md) + +This allows providing documentation for the feature inside the table introduced by +[`feature-metadata`](#feature-metadata): + +```toml +[features.serde] +enables = [] +doc = "Enables support for serialization and deserialization via serde." +``` + +The documentation can be consumed and displayed by tools. +It can be a multi-line TOML string, contain multiple paragraphs, and use Markdown markup, +similarly to Rust doc comments. +Tools may only display the first paragraph in some contexts, which should therefore be +relatively short and make sense without the rest of the description. + ## lockfile-path Support for `resolver.lockfile-path` config field has been stabilized in Rust 1.97.0. diff --git a/tests/testsuite/features.rs b/tests/testsuite/features.rs index fd8628d19d5..8af120a460f 100644 --- a/tests/testsuite/features.rs +++ b/tests/testsuite/features.rs @@ -2682,6 +2682,39 @@ c = [ ); } +#[cargo_test] +fn feature_documentation_is_unstable() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + edition = "2015" + + [features] + foo = { enables = [], doc = "Enables foo." } + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .with_status(101) + .with_stderr_data(str![[r#" +[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` + +Caused by: + feature `feature-metadata` is required + + The package requires the Cargo feature called `feature-metadata`, but that feature is not stabilized in this version of Cargo ([..]). + Consider trying a newer version of Cargo (this may require the nightly release). + See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#feature_metadata for more information about the status of this feature. + +"#]]) + .run(); +} + #[cargo_test] fn feature_has_documentation() { let p = project() @@ -2704,8 +2737,6 @@ fn feature_has_documentation() { p.cargo("check") .masquerade_as_nightly_cargo(&["feature-metadata"]) .with_stderr_data(str![[r#" -[WARNING] Cargo.toml: unused manifest key: `features.foo.doc` -[WARNING] `foo` (manifest) generated 1 warning [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s From 223796b2a5df0a90beb3541d412290a89ac4475a Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 14 Sep 2026 10:54:38 -0400 Subject: [PATCH 3/3] docs(unstable): `feature-metadata` is the umbrella feature --- doc/book/src/reference/unstable.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/doc/book/src/reference/unstable.md b/doc/book/src/reference/unstable.md index 6a36842ce50..ad4d537d1e0 100644 --- a/doc/book/src/reference/unstable.md +++ b/doc/book/src/reference/unstable.md @@ -2384,27 +2384,39 @@ The `pubtime` index field has been stabilized in Rust 1.94.0. ## feature-metadata * Tracking Issue: [#14157](https://github.com/rust-lang/cargo/issues/14157) +* RFC: [#3416](https://github.com/rust-lang/rfcs/blob/master/text/3416-feature-metadata.md) -This allows to use a table when defining features, with a required `enables` key: +This allows defining features with a metadata table. ```toml +cargo-features = ["feature-metadata"] + +[package] +# ... + [features] # same as `foo = []` foo = { enables = [] } ``` -This is equivalent to the array-of-strings syntax. -Support for other keys should be added later. +The required `enables` field is equivalent to the array-of-strings syntax. + +For other metadata fields, see the subsections below. ### feature-documentation * Tracking Issue: [#17445](https://github.com/rust-lang/cargo/issues/17445) * RFC: [#3485](https://github.com/rust-lang/rfcs/blob/master/text/3485-feature-documentation.md) -This allows providing documentation for the feature inside the table introduced by -[`feature-metadata`](#feature-metadata): +This adds a `doc` field to the feature table, +which provides documentation for the feature. ```toml +cargo-features = ["feature-metadata"] + +[package] +# ... + [features.serde] enables = [] doc = "Enables support for serialization and deserialization via serde."