Skip to content

Commit 8f8f814

Browse files
committed
Add the future edition
This adds support for the "future" edition which was added to rustc in rust-lang/rust#137606. To enable support for unstable editions, this introduces a new `unstable-edition` cargo feature. The intent is that instead of having a new feature for each edition that we reuse this feature for all new editions. I don't see a particular reason we should have a separate one for each edition, and this helps a bit with scalability and simplifies some of the edition process. This also includes a change to rework `supports_compat_lint` explained in the comment.
1 parent 68db374 commit 8f8f814

File tree

5 files changed

+127
-25
lines changed

5 files changed

+127
-25
lines changed

src/cargo/core/features.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,17 @@ pub enum Edition {
196196
Edition2021,
197197
/// The 2024 edition
198198
Edition2024,
199+
/// The future edition (permanently unstable)
200+
EditionFuture,
199201
}
200202

201203
impl Edition {
202204
/// The latest edition that is unstable.
203205
///
204206
/// This is `None` if there is no next unstable edition.
207+
///
208+
/// Note that this does *not* include "future" since this is primarily
209+
/// used for tests that need to step between stable and unstable.
205210
pub const LATEST_UNSTABLE: Option<Edition> = None;
206211
/// The latest stable edition.
207212
pub const LATEST_STABLE: Edition = Edition::Edition2024;
@@ -210,11 +215,15 @@ impl Edition {
210215
Self::Edition2018,
211216
Self::Edition2021,
212217
Self::Edition2024,
218+
Self::EditionFuture,
213219
];
214220
/// Possible values allowed for the `--edition` CLI flag.
215221
///
216222
/// This requires a static value due to the way clap works, otherwise I
217223
/// would have built this dynamically.
224+
///
225+
/// This does not include `future` since we don't need to create new
226+
/// projects with it.
218227
pub const CLI_VALUES: [&'static str; 4] = ["2015", "2018", "2021", "2024"];
219228

220229
/// Returns the first version that a particular edition was released on
@@ -226,6 +235,7 @@ impl Edition {
226235
Edition2018 => Some(semver::Version::new(1, 31, 0)),
227236
Edition2021 => Some(semver::Version::new(1, 56, 0)),
228237
Edition2024 => Some(semver::Version::new(1, 85, 0)),
238+
EditionFuture => None,
229239
}
230240
}
231241

@@ -237,6 +247,7 @@ impl Edition {
237247
Edition2018 => true,
238248
Edition2021 => true,
239249
Edition2024 => true,
250+
EditionFuture => false,
240251
}
241252
}
242253

@@ -250,18 +261,21 @@ impl Edition {
250261
Edition2018 => Some(Edition2015),
251262
Edition2021 => Some(Edition2018),
252263
Edition2024 => Some(Edition2021),
264+
EditionFuture => panic!("future does not have a previous edition"),
253265
}
254266
}
255267

256268
/// Returns the next edition from this edition, returning the last edition
257269
/// if this is already the last one.
258270
pub fn saturating_next(&self) -> Edition {
259271
use Edition::*;
272+
// Nothing should treat "future" as being next.
260273
match self {
261274
Edition2015 => Edition2018,
262275
Edition2018 => Edition2021,
263276
Edition2021 => Edition2024,
264277
Edition2024 => Edition2024,
278+
EditionFuture => EditionFuture,
265279
}
266280
}
267281

@@ -274,18 +288,23 @@ impl Edition {
274288
}
275289
}
276290

277-
/// Whether or not this edition supports the `rust_*_compatibility` lint.
278-
///
279-
/// Ideally this would not be necessary, but editions may not have any
280-
/// lints, and thus `rustc` doesn't recognize it. Perhaps `rustc` could
281-
/// create an empty group instead?
282-
pub(crate) fn supports_compat_lint(&self) -> bool {
291+
/// Adds the appropriate argument to generate warnings for this edition.
292+
pub(crate) fn force_warn_arg(&self, cmd: &mut ProcessBuilder) {
283293
use Edition::*;
284294
match self {
285-
Edition2015 => false,
286-
Edition2018 => true,
287-
Edition2021 => true,
288-
Edition2024 => true,
295+
Edition2015 => {}
296+
EditionFuture => {
297+
cmd.arg("--force-warn=edition_future_compatibility");
298+
}
299+
e => {
300+
// Note that cargo always passes this even if the
301+
// compatibility lint group does not exist. When a new edition
302+
// is introduced, but there are no migration lints, rustc does
303+
// not create the lint group. That's OK because rustc will
304+
// just generate a warning about an unknown lint which will be
305+
// suppressed due to cap-lints.
306+
cmd.arg(format!("--force-warn=rust-{e}-compatibility"));
307+
}
289308
}
290309
}
291310

@@ -299,6 +318,7 @@ impl Edition {
299318
Edition2018 => true,
300319
Edition2021 => false,
301320
Edition2024 => false,
321+
EditionFuture => false,
302322
}
303323
}
304324

@@ -320,6 +340,7 @@ impl fmt::Display for Edition {
320340
Edition::Edition2018 => f.write_str("2018"),
321341
Edition::Edition2021 => f.write_str("2021"),
322342
Edition::Edition2024 => f.write_str("2024"),
343+
Edition::EditionFuture => f.write_str("future"),
323344
}
324345
}
325346
}
@@ -332,6 +353,7 @@ impl FromStr for Edition {
332353
"2018" => Ok(Edition::Edition2018),
333354
"2021" => Ok(Edition::Edition2021),
334355
"2024" => Ok(Edition::Edition2024),
356+
"future" => Ok(Edition::EditionFuture),
335357
s if s.parse().map_or(false, |y: u16| y > 2024 && y < 2050) => bail!(
336358
"this version of Cargo is older than the `{}` edition, \
337359
and only supports `2015`, `2018`, `2021`, and `2024` editions.",
@@ -519,6 +541,9 @@ features! {
519541

520542
/// Allow paths that resolve relatively to a base specified in the config.
521543
(unstable, path_bases, "", "reference/unstable.html#path-bases"),
544+
545+
/// Allows use of editions that are not yet stable.
546+
(unstable, unstable_edition, "", "reference/unstable.html#unstable-edition"),
522547
}
523548

524549
/// Status and metadata for a single unstable feature.

src/cargo/ops/fix.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,10 +1238,7 @@ impl FixArgs {
12381238
}
12391239

12401240
if let Some(edition) = self.prepare_for_edition {
1241-
if edition.supports_compat_lint() {
1242-
cmd.arg("--force-warn")
1243-
.arg(format!("rust-{}-compatibility", edition));
1244-
}
1241+
edition.force_warn_arg(cmd);
12451242
}
12461243
}
12471244

src/cargo/util/toml/mod.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,18 +1342,8 @@ pub fn to_real_manifest(
13421342
}
13431343
default_edition
13441344
};
1345-
// Add these lines if start a new unstable edition.
1346-
// ```
1347-
// if edition == Edition::Edition20xx {
1348-
// features.require(Feature::edition20xx())?;
1349-
// }
1350-
// ```
13511345
if !edition.is_stable() {
1352-
// Guard in case someone forgets to add .require()
1353-
return Err(util::errors::internal(format!(
1354-
"edition {} should be gated",
1355-
edition
1356-
)));
1346+
features.require(Feature::unstable_edition())?;
13571347
}
13581348

13591349
if original_toml.project.is_some() {

src/doc/src/reference/unstable.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ Each new feature described below should explain how to use it.
107107
* [Profile `trim-paths` option](#profile-trim-paths-option) --- Control the sanitization of file paths in build outputs.
108108
* [`[lints.cargo]`](#lintscargo) --- Allows configuring lints for Cargo.
109109
* [path bases](#path-bases) --- Named base directories for path dependencies.
110+
* [`unstable-edition`](#unstable-edition) --- Allows use of editions that are not yet stable.
110111
* Information and metadata
111112
* [Build-plan](#build-plan) --- Emits JSON information on which commands will be run.
112113
* [unit-graph](#unit-graph) --- Emits JSON for Cargo's internal graph structure.
@@ -1898,6 +1899,22 @@ be stored in `.rmeta` files.
18981899
cargo +nightly -Zno-embed-metadata build
18991900
```
19001901

1902+
## `unstable-edition`
1903+
1904+
The `unstable-edition` value in the `cargo-features` list allows a `Cargo.toml` manifest to specify an edition that is not yet stable.
1905+
1906+
```toml
1907+
cargo-features = ["unstable-edition"]
1908+
1909+
[package]
1910+
name = "my-package"
1911+
edition = "future"
1912+
```
1913+
1914+
When new editions are introduced, the `unstable-edition` feature is required until the edition is stabilized.
1915+
1916+
The special "future" edition is a home for new features that are under development, and is permanently unstable. The "future" edition also has no new behavior by itself. Each change in the future edition requires an opt-in such as a `#![feature(...)]` attribute.
1917+
19011918
# Stabilized and removed features
19021919

19031920
## Compile progress

tests/testsuite/edition.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,76 @@ fn unset_edition_works_on_old_msrv() {
194194
"#]])
195195
.run();
196196
}
197+
198+
#[cargo_test]
199+
fn future_edition_is_gated() {
200+
let p = project()
201+
.file(
202+
"Cargo.toml",
203+
r#"
204+
[package]
205+
name = "foo"
206+
edition = "future"
207+
"#,
208+
)
209+
.file("src/lib.rs", "")
210+
.build();
211+
212+
p.cargo("check")
213+
.with_status(101)
214+
.with_stderr_data(str![[r#"
215+
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
216+
217+
Caused by:
218+
feature `unstable-edition` is required
219+
220+
The package requires the Cargo feature called `unstable-edition`, but that feature is not stabilized in this version of Cargo ([..]).
221+
Consider trying a newer version of Cargo (this may require the nightly release).
222+
See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#unstable-edition for more information about the status of this feature.
223+
224+
"#]])
225+
.run();
226+
227+
// Repeat on nightly.
228+
p.cargo("check")
229+
.masquerade_as_nightly_cargo(&["unstable-edition"])
230+
.with_status(101)
231+
.with_stderr_data(str![[r#"
232+
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
233+
234+
Caused by:
235+
feature `unstable-edition` is required
236+
237+
The package requires the Cargo feature called `unstable-edition`, but that feature is not stabilized in this version of Cargo ([..]).
238+
Consider adding `cargo-features = ["unstable-edition"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature.
239+
See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#unstable-edition for more information about the status of this feature.
240+
241+
"#]])
242+
.run();
243+
}
244+
245+
#[cargo_test(nightly, reason = "future edition is always unstable")]
246+
fn future_edition_works() {
247+
let p = project()
248+
.file(
249+
"Cargo.toml",
250+
r#"
251+
cargo-features = ["unstable-edition"]
252+
253+
[package]
254+
name = "foo"
255+
edition = "future"
256+
"#,
257+
)
258+
.file("src/lib.rs", "")
259+
.build();
260+
261+
p.cargo("check")
262+
.masquerade_as_nightly_cargo(&["unstable-edition"])
263+
.with_stderr_data(str![[r#"
264+
[CHECKING] foo v0.0.0 ([ROOT]/foo)
265+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
266+
267+
"#]])
268+
.run();
269+
}

0 commit comments

Comments
 (0)