Skip to content

Commit 56ee620

Browse files
committedSep 6, 2018
Auto merge of #5984 - alexcrichton:stabilize-edition, r=ehuss
Stabilize `edition` key and add `cargo new --edition` This commit stabilizes the `edition` key in `Cargo.toml`, both in the `[package]` section and inside subtargets. Additionally the `cargo new` and `cargo init` subcommands have been enhanced with a `--edition` flag to allow explicitly specifying the edition to be generated. This commit does not yet change the default edition that's generated. Closes #5980
2 parents a39c2a3 + 3d02903 commit 56ee620

File tree

13 files changed

+158
-229
lines changed

13 files changed

+158
-229
lines changed
 

‎src/bin/cargo/command_prelude.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,14 @@ pub trait AppExt: Sized {
147147
a global configuration.",
148148
).value_name("VCS")
149149
.possible_values(&["git", "hg", "pijul", "fossil", "none"]),
150-
)._arg(opt("bin", "Use a binary (application) template [default]"))
150+
)
151+
._arg(opt("bin", "Use a binary (application) template [default]"))
151152
._arg(opt("lib", "Use a library template"))
153+
._arg(
154+
opt("edition", "Edition to set for the crate generated")
155+
.possible_values(&["2015", "2018"])
156+
.value_name("YEAR")
157+
)
152158
._arg(
153159
opt(
154160
"name",
@@ -339,6 +345,7 @@ pub trait ArgMatchesExt {
339345
self._is_present("lib"),
340346
self.value_of_path("path", config).unwrap(),
341347
self._value_of("name").map(|s| s.to_string()),
348+
self._value_of("edition").map(|s| s.to_string()),
342349
)
343350
}
344351

‎src/cargo/core/compiler/compilation.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::path::PathBuf;
66
use semver::Version;
77
use lazycell::LazyCell;
88

9-
use core::{Feature, Package, PackageId, Target, TargetKind};
9+
use core::{Edition, Package, PackageId, Target, TargetKind};
1010
use util::{self, join_paths, process, CargoResult, Config, ProcessBuilder};
1111
use super::BuildContext;
1212

@@ -131,8 +131,7 @@ impl<'cfg> Compilation<'cfg> {
131131
/// See `process`.
132132
pub fn rustc_process(&self, pkg: &Package, target: &Target) -> CargoResult<ProcessBuilder> {
133133
let mut p = self.fill_env(self.rustc_process.clone(), pkg, true)?;
134-
let manifest = pkg.manifest();
135-
if manifest.features().is_enabled(Feature::edition()) {
134+
if target.edition() != Edition::Edition2015 {
136135
p.arg(format!("--edition={}", target.edition()));
137136
}
138137
Ok(p)
@@ -141,8 +140,7 @@ impl<'cfg> Compilation<'cfg> {
141140
/// See `process`.
142141
pub fn rustdoc_process(&self, pkg: &Package, target: &Target) -> CargoResult<ProcessBuilder> {
143142
let mut p = self.fill_env(process(&*self.config.rustdoc()?), pkg, false)?;
144-
let manifest = pkg.manifest();
145-
if manifest.features().is_enabled(Feature::edition()) {
143+
if target.edition() != Edition::Edition2015 {
146144
p.arg("-Zunstable-options");
147145
p.arg(format!("--edition={}", target.edition()));
148146
}

‎src/cargo/core/features.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl FromStr for Edition {
8585
}
8686
}
8787

88+
#[derive(PartialEq)]
8889
enum Status {
8990
Stable,
9091
Unstable,
@@ -106,7 +107,7 @@ macro_rules! features {
106107
$(
107108
pub fn $feature() -> &'static Feature {
108109
fn get(features: &Features) -> bool {
109-
features.$feature
110+
stab!($stab) == Status::Stable || features.$feature
110111
}
111112
static FEAT: Feature = Feature {
112113
name: stringify!($feature),
@@ -173,7 +174,7 @@ features! {
173174
[unstable] alternative_registries: bool,
174175

175176
// Using editions
176-
[unstable] edition: bool,
177+
[stable] edition: bool,
177178

178179
// Renaming a package in the manifest via the `package` key
179180
[unstable] rename_dependency: bool,

‎src/cargo/ops/cargo_new.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub struct NewOptions {
3030
/// Absolute path to the directory for the new project
3131
pub path: PathBuf,
3232
pub name: Option<String>,
33+
pub edition: Option<String>,
3334
}
3435

3536
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -65,6 +66,7 @@ struct MkOptions<'a> {
6566
name: &'a str,
6667
source_files: Vec<SourceFileInformation>,
6768
bin: bool,
69+
edition: Option<&'a str>,
6870
}
6971

7072
impl NewOptions {
@@ -74,6 +76,7 @@ impl NewOptions {
7476
lib: bool,
7577
path: PathBuf,
7678
name: Option<String>,
79+
edition: Option<String>,
7780
) -> CargoResult<NewOptions> {
7881
let kind = match (bin, lib) {
7982
(true, true) => bail!("can't specify both lib and binary outputs"),
@@ -87,6 +90,7 @@ impl NewOptions {
8790
kind,
8891
path,
8992
name,
93+
edition,
9094
};
9195
Ok(opts)
9296
}
@@ -321,6 +325,7 @@ pub fn new(opts: &NewOptions, config: &Config) -> CargoResult<()> {
321325
name,
322326
source_files: vec![plan_new_source_file(opts.kind.is_bin(), name.to_string())],
323327
bin: opts.kind.is_bin(),
328+
edition: opts.edition.as_ref().map(|s| &**s),
324329
};
325330

326331
mk(config, &mkopts).chain_err(|| {
@@ -397,6 +402,7 @@ pub fn init(opts: &NewOptions, config: &Config) -> CargoResult<()> {
397402
name,
398403
bin: src_paths_types.iter().any(|x| x.bin),
399404
source_files: src_paths_types,
405+
edition: opts.edition.as_ref().map(|s| &**s),
400406
};
401407

402408
mk(config, &mkopts).chain_err(|| {
@@ -529,12 +535,19 @@ path = {}
529535
r#"[package]
530536
name = "{}"
531537
version = "0.1.0"
532-
authors = [{}]
538+
authors = [{}]{}
533539
534540
[dependencies]
535541
{}"#,
536542
name,
537543
toml::Value::String(author),
544+
match opts.edition {
545+
Some(edition) => {
546+
let edition = toml::Value::String(edition.to_string());
547+
format!("\nedition = {}", edition)
548+
}
549+
None => String::new(),
550+
},
538551
cargotoml_path_specifier
539552
).as_bytes(),
540553
)?;

‎src/doc/src/reference/manifest.md

+24
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,24 @@ Versioning](http://semver.org/), so make sure you follow some basic rules:
3131
traits, fields, types, functions, methods or anything else.
3232
* Use version numbers with three numeric parts such as 1.0.0 rather than 1.0.
3333

34+
#### The `edition` field (optional)
35+
36+
You can opt in to a specific Rust Edition for your package with the
37+
`edition` key in `Cargo.toml`. If you don't specify the edition, it will
38+
default to 2015.
39+
40+
```toml
41+
[package]
42+
# ...
43+
edition = '2018'
44+
```
45+
46+
The `edition` key affects which edition your package is compiled with. Cargo
47+
will always generate projects via `cargo new` with the `edition` key set to the
48+
latest edition. Setting the `edition` key in `[package]` will affect all
49+
targets/crates in the package, including test suites, benchmarks, binaries,
50+
examples, etc.
51+
3452
#### The `build` field (optional)
3553

3654
This field specifies a file in the project root which is a [build script][1] for
@@ -714,6 +732,12 @@ proc-macro = false
714732
# stops it from generating a test harness. This is useful when the binary being
715733
# built manages the test runner itself.
716734
harness = true
735+
736+
# If set then a target can be configured to use a different edition than the
737+
# `[package]` is configured to use, perhaps only compiling a library with the
738+
# 2018 edition or only compiling one unit test with the 2015 edition. By default
739+
# all targets are compiled with the edition specified in `[package]`.
740+
edition = '2015'
717741
```
718742

719743
The `[package]` also includes the optional `autobins`, `autoexamples`,

‎src/doc/src/reference/unstable.md

-24
Original file line numberDiff line numberDiff line change
@@ -199,30 +199,6 @@ cargo +nightly build --out-dir=out -Z unstable-options
199199
```
200200

201201

202-
### Edition
203-
* Tracking Issue: [rust-lang/rust#44581](https://github.com/rust-lang/rust/issues/44581)
204-
* RFC: [#2052](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md)
205-
206-
You can opt in to a specific Rust Edition for your package with the `edition`
207-
key in `Cargo.toml`. If you don't specify the edition, it will default to
208-
2015. You need to include the appropriate `cargo-features`.
209-
210-
You can also specify `edition` on a per-target level, where it will otherwise
211-
default to the package `edition`.
212-
213-
```toml
214-
cargo-features = ["edition"]
215-
216-
[package]
217-
...
218-
edition = "2018"
219-
220-
[[bin]]
221-
...
222-
edition = "2015"
223-
```
224-
225-
226202
### Profile Overrides
227203
* Tracking Issue: [rust-lang/rust#48683](https://github.com/rust-lang/rust/issues/48683)
228204
* RFC: [#2282](https://github.com/rust-lang/rfcs/blob/master/text/2282-profile-dependencies.md)

‎tests/testsuite/bench.rs

+24-27
Original file line numberDiff line numberDiff line change
@@ -549,45 +549,42 @@ fn bench_autodiscover_2015() {
549549
.file(
550550
"Cargo.toml",
551551
r#"
552-
cargo-features = ["edition"]
553-
554-
[project]
555-
name = "foo"
556-
version = "0.0.1"
557-
authors = []
558-
edition = "2015"
559-
560-
[[bench]]
561-
name = "bench_magic"
562-
required-features = ["magic"]
563-
"#,
552+
[project]
553+
name = "foo"
554+
version = "0.0.1"
555+
authors = []
556+
edition = "2015"
557+
558+
[[bench]]
559+
name = "bench_magic"
560+
required-features = ["magic"]
561+
"#,
564562
).file("src/lib.rs", "")
565563
.file(
566564
"benches/bench_basic.rs",
567565
r#"
568-
#![feature(test)]
569-
#[allow(unused_extern_crates)]
570-
extern crate foo;
571-
extern crate test;
566+
#![feature(test)]
567+
#[allow(unused_extern_crates)]
568+
extern crate foo;
569+
extern crate test;
572570
573-
#[bench]
574-
fn bench_basic(_b: &mut test::Bencher) {}
575-
"#,
571+
#[bench]
572+
fn bench_basic(_b: &mut test::Bencher) {}
573+
"#,
576574
).file(
577575
"benches/bench_magic.rs",
578576
r#"
579-
#![feature(test)]
580-
#[allow(unused_extern_crates)]
581-
extern crate foo;
582-
extern crate test;
577+
#![feature(test)]
578+
#[allow(unused_extern_crates)]
579+
extern crate foo;
580+
extern crate test;
583581
584-
#[bench]
585-
fn bench_magic(_b: &mut test::Bencher) {}
586-
"#,
582+
#[bench]
583+
fn bench_magic(_b: &mut test::Bencher) {}
584+
"#,
587585
).build();
588586

589587
p.cargo("bench bench_basic")
590-
.masquerade_as_nightly_cargo()
591588
.with_stderr(
592589
"warning: \
593590
An explicit [[bench]] section is specified in Cargo.toml which currently

‎tests/testsuite/build.rs

+23-61
Original file line numberDiff line numberDiff line change
@@ -3928,19 +3928,17 @@ fn target_edition() {
39283928
.file(
39293929
"Cargo.toml",
39303930
r#"
3931-
cargo-features = ["edition"]
3932-
[package]
3933-
name = "foo"
3934-
version = "0.0.1"
3931+
[package]
3932+
name = "foo"
3933+
version = "0.0.1"
39353934
3936-
[lib]
3937-
edition = "2018"
3938-
"#,
3935+
[lib]
3936+
edition = "2018"
3937+
"#,
39393938
).file("src/lib.rs", "")
39403939
.build();
39413940

39423941
p.cargo("build -v")
3943-
.masquerade_as_nightly_cargo()
39443942
.with_stderr_contains(
39453943
"\
39463944
[COMPILING] foo v0.0.1 ([..])
@@ -3955,62 +3953,26 @@ fn target_edition_override() {
39553953
.file(
39563954
"Cargo.toml",
39573955
r#"
3958-
cargo-features = ["edition"]
3959-
[package]
3960-
name = "foo"
3961-
version = "0.0.1"
3962-
authors = []
3963-
edition = "2018"
3964-
3965-
[lib]
3966-
edition = "2015"
3967-
"#,
3968-
).file("src/lib.rs", "")
3969-
.build();
3970-
3971-
p.cargo("build -v")
3972-
.masquerade_as_nightly_cargo()
3973-
.with_stderr_contains(
3974-
"\
3975-
[COMPILING] foo v0.0.1 ([..])
3976-
[RUNNING] `rustc [..]--edition=2015 [..]
3977-
",
3978-
).run();
3979-
}
3980-
3981-
#[test]
3982-
fn target_edition_feature_gated() {
3983-
let p = project()
3984-
.file(
3985-
"Cargo.toml",
3986-
r#"
3987-
[package]
3988-
name = "foo"
3989-
version = "0.0.1"
3990-
authors = []
3956+
[package]
3957+
name = "foo"
3958+
version = "0.0.1"
3959+
authors = []
3960+
edition = "2018"
39913961
3992-
[lib]
3993-
edition = "2018"
3994-
"#,
3995-
).file("src/lib.rs", "")
3962+
[lib]
3963+
edition = "2015"
3964+
"#,
3965+
).file(
3966+
"src/lib.rs",
3967+
"
3968+
pub fn async() {}
3969+
pub fn try() {}
3970+
pub fn await() {}
3971+
"
3972+
)
39963973
.build();
39973974

3998-
p.cargo("build -v")
3999-
.masquerade_as_nightly_cargo()
4000-
.with_status(101)
4001-
.with_stderr(
4002-
"\
4003-
error: failed to parse manifest at `[..]`
4004-
4005-
Caused by:
4006-
editions are unstable
4007-
4008-
Caused by:
4009-
feature `edition` is required
4010-
4011-
consider adding `cargo-features = [\"edition\"]` to the manifest
4012-
",
4013-
).run();
3975+
p.cargo("build -v").run();
40143976
}
40153977

40163978
#[test]

‎tests/testsuite/edition.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ fn edition_works_for_build_script() {
1010
.file(
1111
"Cargo.toml",
1212
r#"
13-
cargo-features = ['edition']
1413
[package]
1514
name = 'foo'
1615
version = '0.1.0'

‎tests/testsuite/fix.rs

-8
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,6 @@ fn upgrade_extern_crate() {
355355
.file(
356356
"Cargo.toml",
357357
r#"
358-
cargo-features = ["edition"]
359-
360358
[package]
361359
name = "foo"
362360
version = "0.1.0"
@@ -392,7 +390,6 @@ fn upgrade_extern_crate() {
392390
";
393391
p.cargo("fix --allow-no-vcs")
394392
.env("__CARGO_FIX_YOLO", "1")
395-
.masquerade_as_nightly_cargo()
396393
.with_stderr(stderr)
397394
.with_stdout("")
398395
.run();
@@ -830,8 +827,6 @@ fn prepare_for_and_enable() {
830827
.file(
831828
"Cargo.toml",
832829
r#"
833-
cargo-features = ['edition']
834-
835830
[package]
836831
name = 'foo'
837832
version = '0.1.0'
@@ -853,7 +848,6 @@ information about transitioning to the 2018 edition see:
853848
854849
";
855850
p.cargo("fix --edition --allow-no-vcs")
856-
.masquerade_as_nightly_cargo()
857851
.with_stderr_contains(stderr)
858852
.with_status(101)
859853
.run();
@@ -925,7 +919,6 @@ fn fix_idioms() {
925919
.file(
926920
"Cargo.toml",
927921
r#"
928-
cargo-features = ['edition']
929922
[package]
930923
name = 'foo'
931924
version = '0.1.0'
@@ -947,7 +940,6 @@ fn fix_idioms() {
947940
[FINISHED] [..]
948941
";
949942
p.cargo("fix --edition-idioms --allow-no-vcs")
950-
.masquerade_as_nightly_cargo()
951943
.with_stderr(stderr)
952944
.with_status(0)
953945
.run();

‎tests/testsuite/new.rs

+27
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,30 @@ fn explicit_project_name() {
455455
.with_stderr("[CREATED] library `bar` project")
456456
.run();
457457
}
458+
459+
#[test]
460+
fn new_with_edition_2015() {
461+
cargo_process("new --edition 2015 foo")
462+
.env("USER", "foo")
463+
.run();
464+
let manifest = fs::read_to_string(paths::root().join("foo/Cargo.toml")).unwrap();
465+
assert!(manifest.contains("edition = \"2015\""));
466+
}
467+
468+
#[test]
469+
fn new_with_edition_2018() {
470+
cargo_process("new --edition 2018 foo")
471+
.env("USER", "foo")
472+
.run();
473+
let manifest = fs::read_to_string(paths::root().join("foo/Cargo.toml")).unwrap();
474+
assert!(manifest.contains("edition = \"2018\""));
475+
}
476+
477+
#[test]
478+
fn new_with_bad_edition() {
479+
cargo_process("new --edition something_else foo")
480+
.env("USER", "foo")
481+
.with_stderr_contains("error: 'something_else' isn't a valid value[..]")
482+
.with_status(1)
483+
.run();
484+
}

‎tests/testsuite/package.rs

+16-77
Original file line numberDiff line numberDiff line change
@@ -971,45 +971,19 @@ fn edition_with_metadata() {
971971
.file(
972972
"Cargo.toml",
973973
r#"
974-
cargo-features = ["edition"]
975-
[package]
976-
name = "foo"
977-
version = "0.0.1"
978-
authors = []
979-
edition = "2018"
980-
[package.metadata.docs.rs]
981-
features = ["foobar"]
982-
"#,
974+
[package]
975+
name = "foo"
976+
version = "0.0.1"
977+
authors = []
978+
edition = "2018"
979+
980+
[package.metadata.docs.rs]
981+
features = ["foobar"]
982+
"#,
983983
).file("src/lib.rs", "")
984984
.build();
985985

986-
p.cargo("package").masquerade_as_nightly_cargo().run();
987-
}
988-
989-
#[test]
990-
fn test_edition_missing() {
991-
// no edition = 2015
992-
let p = project()
993-
.file(
994-
"Cargo.toml",
995-
r#"
996-
cargo-features = ["edition"]
997-
[package]
998-
name = "foo"
999-
version = "0.0.1"
1000-
authors = []
1001-
"#,
1002-
).file("src/lib.rs", r#" "#)
1003-
.build();
1004-
1005-
p.cargo("build -v").masquerade_as_nightly_cargo()
1006-
// --edition is still in flux and we're not passing -Zunstable-options
1007-
// from Cargo so it will probably error. Only partially match the output
1008-
// until stuff stabilizes
1009-
.with_stderr_contains("\
1010-
[COMPILING] foo v0.0.1 ([..])
1011-
[RUNNING] `rustc [..]--edition=2015 [..]
1012-
").run();
986+
p.cargo("package").run();
1013987
}
1014988

1015989
#[test]
@@ -1018,18 +992,16 @@ fn test_edition_malformed() {
1018992
.file(
1019993
"Cargo.toml",
1020994
r#"
1021-
cargo-features = ["edition"]
1022-
[package]
1023-
name = "foo"
1024-
version = "0.0.1"
1025-
authors = []
1026-
edition = "chicken"
1027-
"#,
995+
[package]
996+
name = "foo"
997+
version = "0.0.1"
998+
authors = []
999+
edition = "chicken"
1000+
"#,
10281001
).file("src/lib.rs", r#" "#)
10291002
.build();
10301003

10311004
p.cargo("build -v")
1032-
.masquerade_as_nightly_cargo()
10331005
.with_status(101)
10341006
.with_stderr(
10351007
"\
@@ -1044,39 +1016,6 @@ Caused by:
10441016
).run();
10451017
}
10461018

1047-
#[test]
1048-
fn test_edition_nightly() {
1049-
let p = project()
1050-
.file(
1051-
"Cargo.toml",
1052-
r#"
1053-
[package]
1054-
name = "foo"
1055-
version = "0.0.1"
1056-
authors = []
1057-
edition = "2015"
1058-
"#,
1059-
).file("src/lib.rs", r#" "#)
1060-
.build();
1061-
1062-
p.cargo("build -v")
1063-
.masquerade_as_nightly_cargo()
1064-
.with_status(101)
1065-
.with_stderr(
1066-
"\
1067-
error: failed to parse manifest at `[..]`
1068-
1069-
Caused by:
1070-
editions are unstable
1071-
1072-
Caused by:
1073-
feature `edition` is required
1074-
1075-
consider adding `cargo-features = [\"edition\"]` to the manifest
1076-
",
1077-
).run();
1078-
}
1079-
10801019
#[test]
10811020
fn package_lockfile() {
10821021
let p = project()

‎tests/testsuite/run.rs

+16-22
Original file line numberDiff line numberDiff line change
@@ -359,31 +359,29 @@ fn autodiscover_examples_project(rust_edition: &str, autoexamples: Option<bool>)
359359
"Cargo.toml",
360360
&format!(
361361
r#"
362-
cargo-features = ["edition"]
363-
364-
[project]
365-
name = "foo"
366-
version = "0.0.1"
367-
authors = []
368-
edition = "{rust_edition}"
369-
{autoexamples}
370-
371-
[features]
372-
magic = []
373-
374-
[[example]]
375-
name = "do_magic"
376-
required-features = ["magic"]
377-
"#,
362+
[project]
363+
name = "foo"
364+
version = "0.0.1"
365+
authors = []
366+
edition = "{rust_edition}"
367+
{autoexamples}
368+
369+
[features]
370+
magic = []
371+
372+
[[example]]
373+
name = "do_magic"
374+
required-features = ["magic"]
375+
"#,
378376
rust_edition = rust_edition,
379377
autoexamples = autoexamples
380378
),
381379
).file("examples/a.rs", r#"fn main() { println!("example"); }"#)
382380
.file(
383381
"examples/do_magic.rs",
384382
r#"
385-
fn main() { println!("magic example"); }
386-
"#,
383+
fn main() { println!("magic example"); }
384+
"#,
387385
).build()
388386
}
389387

@@ -395,7 +393,6 @@ fn run_example_autodiscover_2015() {
395393

396394
let p = autodiscover_examples_project("2015", None);
397395
p.cargo("run --example a")
398-
.masquerade_as_nightly_cargo()
399396
.with_status(101)
400397
.with_stderr(
401398
"warning: \
@@ -427,7 +424,6 @@ fn run_example_autodiscover_2015_with_autoexamples_enabled() {
427424

428425
let p = autodiscover_examples_project("2015", Some(true));
429426
p.cargo("run --example a")
430-
.masquerade_as_nightly_cargo()
431427
.with_stderr(
432428
"\
433429
[COMPILING] foo v0.0.1 (CWD)
@@ -445,7 +441,6 @@ fn run_example_autodiscover_2015_with_autoexamples_disabled() {
445441

446442
let p = autodiscover_examples_project("2015", Some(false));
447443
p.cargo("run --example a")
448-
.masquerade_as_nightly_cargo()
449444
.with_status(101)
450445
.with_stderr("error: no example target named `a`\n")
451446
.run();
@@ -459,7 +454,6 @@ fn run_example_autodiscover_2018() {
459454

460455
let p = autodiscover_examples_project("2018", None);
461456
p.cargo("run --example a")
462-
.masquerade_as_nightly_cargo()
463457
.with_stderr(
464458
"\
465459
[COMPILING] foo v0.0.1 (CWD)

0 commit comments

Comments
 (0)
Please sign in to comment.