Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,19 @@ impl Features {

/// Checks if the given feature is enabled.
pub fn require(&self, feature: &Feature) -> CargoResult<()> {
self.require_with_hint(feature, None)
}

/// Like [`require`][Self::require], but appends an optional help message
/// to the error, placed just before the documentation link.
///
/// Use this when the call site has additional context (e.g. the package's
/// `rust-version`) that can make the error more actionable.
pub(crate) fn require_with_hint(
&self,
feature: &Feature,
hint: Option<&str>,
) -> CargoResult<()> {
if feature.is_enabled(self) {
return Ok(());
}
Expand Down Expand Up @@ -773,6 +786,9 @@ impl Features {
about the status of this feature.",
feature.docs
);
if let Some(hint) = hint {
let _ = writeln!(msg, "{hint}");
}

bail!("{}", msg);
}
Expand Down
10 changes: 9 additions & 1 deletion src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,15 @@ pub fn to_real_manifest(
default_edition
};
if !edition.is_stable() {
features.require(Feature::unstable_editions())?;
let version = normalized_package
.normalized_version()
.expect("previously normalized")
.map(|v| format!("@{v}"))
.unwrap_or_default();
let hint = rust_version
.as_ref()
.map(|rv| format!("help: {package_name}{version} requires rust {rv}"));
features.require_with_hint(Feature::unstable_editions(), hint.as_deref())?;
}

if original_toml.project.is_some() {
Expand Down
37 changes: 37 additions & 0 deletions tests/testsuite/edition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,43 @@ Caused by:
.run();
}

#[cargo_test]
fn future_edition_with_rust_version_hint() {
// When an unstable edition is used and the package has `rust-version` set,
// the error message should include a `help:` line pointing the user at the
// required Rust toolchain version, matching the format used elsewhere in
// Cargo (e.g. `{name}@{version} requires rust {msrv}`).
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "future"
rust-version = "1.90"
"#,
)
.file("src/lib.rs", "")
.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 `unstable-editions` is required

The package requires the Cargo feature called `unstable-editions`, 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#unstable-editions for more information about the status of this feature.
[HELP] foo@0.1.0 requires rust 1.90

"#]])
.run();
}

#[cargo_test(nightly, reason = "future edition is always unstable")]
fn future_edition_works() {
let p = project()
Expand Down