Skip to content

Commit 4b95e8c

Browse files
committed
Auto merge of #5816 - dwijnand:edtion-per-target, r=alexcrichton
Edition key should be per-target, not per-package Fixes #5661 I've pushed this WIP PR as I'd love some early feedback on it and some tips on: * how to best to make it fail if edition is set on a target, but the feature isn't set; and * what tests this should include (i.e how exhaustive should I go) Thanks!
2 parents af6e295 + 67c52ff commit 4b95e8c

File tree

10 files changed

+187
-17
lines changed

10 files changed

+187
-17
lines changed

src/cargo/core/compiler/compilation.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,22 +121,22 @@ impl<'cfg> Compilation<'cfg> {
121121
}
122122

123123
/// See `process`.
124-
pub fn rustc_process(&self, pkg: &Package) -> CargoResult<ProcessBuilder> {
124+
pub fn rustc_process(&self, pkg: &Package, target: &Target) -> CargoResult<ProcessBuilder> {
125125
let mut p = self.fill_env(self.rustc_process.clone(), pkg, true)?;
126126
let manifest = pkg.manifest();
127127
if manifest.features().is_enabled(Feature::edition()) {
128-
p.arg(format!("--edition={}", manifest.edition()));
128+
p.arg(format!("--edition={}", target.edition()));
129129
}
130130
Ok(p)
131131
}
132132

133133
/// See `process`.
134-
pub fn rustdoc_process(&self, pkg: &Package) -> CargoResult<ProcessBuilder> {
134+
pub fn rustdoc_process(&self, pkg: &Package, target: &Target) -> CargoResult<ProcessBuilder> {
135135
let mut p = self.fill_env(process(&*self.config.rustdoc()?), pkg, false)?;
136136
let manifest = pkg.manifest();
137137
if manifest.features().is_enabled(Feature::edition()) {
138138
p.arg("-Zunstable-options");
139-
p.arg(format!("--edition={}", &manifest.edition()));
139+
p.arg(format!("--edition={}", target.edition()));
140140
}
141141
Ok(p)
142142
}

src/cargo/core/compiler/fingerprint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ fn calculate<'a, 'cfg>(
479479
deps,
480480
local: vec![local],
481481
memoized_hash: Mutex::new(None),
482-
edition: unit.pkg.manifest().edition(),
482+
edition: unit.target.edition(),
483483
rustflags: extra_flags,
484484
});
485485
cx.fingerprints.insert(*unit, Arc::clone(&fingerprint));

src/cargo/core/compiler/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ fn prepare_rustc<'a, 'cfg>(
563563
crate_types: &[&str],
564564
unit: &Unit<'a>,
565565
) -> CargoResult<ProcessBuilder> {
566-
let mut base = cx.compilation.rustc_process(unit.pkg)?;
566+
let mut base = cx.compilation.rustc_process(unit.pkg, unit.target)?;
567567
base.inherit_jobserver(&cx.jobserver);
568568
build_base_args(cx, &mut base, unit, crate_types)?;
569569
build_deps_args(&mut base, cx, unit)?;
@@ -572,7 +572,7 @@ fn prepare_rustc<'a, 'cfg>(
572572

573573
fn rustdoc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoResult<Work> {
574574
let bcx = cx.bcx;
575-
let mut rustdoc = cx.compilation.rustdoc_process(unit.pkg)?;
575+
let mut rustdoc = cx.compilation.rustdoc_process(unit.pkg, unit.target)?;
576576
rustdoc.inherit_jobserver(&cx.jobserver);
577577
rustdoc.arg("--crate-name").arg(&unit.target.crate_name());
578578
add_path_args(bcx, unit, &mut rustdoc);

src/cargo/core/manifest.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ pub struct Target {
200200
doctest: bool,
201201
harness: bool, // whether to use the test harness (--test)
202202
for_host: bool,
203+
edition: Edition,
203204
}
204205

205206
#[derive(Clone, PartialEq, Eq)]
@@ -280,6 +281,7 @@ compact_debug! {
280281
doctest
281282
harness
282283
for_host
284+
edition
283285
)]
284286
}
285287
}
@@ -507,6 +509,7 @@ impl Target {
507509
doctest: false,
508510
harness: true,
509511
for_host: false,
512+
edition: Edition::Edition2015,
510513
tested: true,
511514
benched: true,
512515
}
@@ -625,6 +628,7 @@ impl Target {
625628
pub fn for_host(&self) -> bool {
626629
self.for_host
627630
}
631+
pub fn edition(&self) -> Edition { self.edition }
628632
pub fn benched(&self) -> bool {
629633
self.benched
630634
}
@@ -746,6 +750,10 @@ impl Target {
746750
self.for_host = for_host;
747751
self
748752
}
753+
pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
754+
self.edition = edition;
755+
self
756+
}
749757
pub fn set_harness(&mut self, harness: bool) -> &mut Target {
750758
self.harness = harness;
751759
self

src/cargo/ops/cargo_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ fn run_doc_tests(
161161
deps,
162162
} = doctest_info;
163163
config.shell().status("Doc-tests", target.name())?;
164-
let mut p = compilation.rustdoc_process(package)?;
164+
let mut p = compilation.rustdoc_process(package, target)?;
165165
p.arg("--test")
166166
.arg(target.src_path())
167167
.arg("--crate-name")

src/cargo/util/toml/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,7 @@ impl TomlManifest {
781781
// If we have a lib with a path, we're done
782782
// If we have a lib with no path, use the inferred lib or_else package name
783783
let targets = targets(
784+
&features,
784785
me,
785786
package_name,
786787
package_root,
@@ -1357,6 +1358,7 @@ struct TomlTarget {
13571358
harness: Option<bool>,
13581359
#[serde(rename = "required-features")]
13591360
required_features: Option<Vec<String>>,
1361+
edition: Option<String>,
13601362
}
13611363

13621364
#[derive(Clone)]

src/cargo/util/toml/targets.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ use std::path::{Path, PathBuf};
1414
use std::fs::{self, DirEntry};
1515
use std::collections::HashSet;
1616

17-
use core::{compiler, Edition, Target};
18-
use util::errors::CargoResult;
17+
use core::{compiler, Edition, Feature, Features, Target};
18+
use util::errors::{CargoResult, CargoResultExt};
1919
use super::{LibKind, PathValue, StringOrBool, TomlBenchTarget, TomlBinTarget, TomlExampleTarget,
2020
TomlLibTarget, TomlManifest, TomlTarget, TomlTestTarget};
2121

2222
pub fn targets(
23+
features: &Features,
2324
manifest: &TomlManifest,
2425
package_name: &str,
2526
package_root: &Path,
@@ -33,6 +34,7 @@ pub fn targets(
3334
let has_lib;
3435

3536
if let Some(target) = clean_lib(
37+
features,
3638
manifest.lib.as_ref(),
3739
package_root,
3840
package_name,
@@ -52,6 +54,7 @@ pub fn targets(
5254
.ok_or_else(|| format_err!("manifest has no `package` (or `project`)"))?;
5355

5456
targets.extend(clean_bins(
57+
features,
5558
manifest.bin.as_ref(),
5659
package_root,
5760
package_name,
@@ -63,6 +66,7 @@ pub fn targets(
6366
)?);
6467

6568
targets.extend(clean_examples(
69+
features,
6670
manifest.example.as_ref(),
6771
package_root,
6872
edition,
@@ -72,6 +76,7 @@ pub fn targets(
7276
)?);
7377

7478
targets.extend(clean_tests(
79+
features,
7580
manifest.test.as_ref(),
7681
package_root,
7782
edition,
@@ -81,6 +86,7 @@ pub fn targets(
8186
)?);
8287

8388
targets.extend(clean_benches(
89+
features,
8490
manifest.bench.as_ref(),
8591
package_root,
8692
edition,
@@ -108,6 +114,7 @@ pub fn targets(
108114
}
109115

110116
fn clean_lib(
117+
features: &Features,
111118
toml_lib: Option<&TomlLibTarget>,
112119
package_root: &Path,
113120
package_name: &str,
@@ -183,11 +190,12 @@ fn clean_lib(
183190
};
184191

185192
let mut target = Target::lib_target(&lib.name(), crate_types, path);
186-
configure(lib, &mut target);
193+
configure(features, lib, &mut target, edition)?;
187194
Ok(Some(target))
188195
}
189196

190197
fn clean_bins(
198+
features: &Features,
191199
toml_bins: Option<&Vec<TomlBinTarget>>,
192200
package_root: &Path,
193201
package_name: &str,
@@ -263,7 +271,7 @@ fn clean_bins(
263271
};
264272

265273
let mut target = Target::bin_target(&bin.name(), path, bin.required_features.clone());
266-
configure(bin, &mut target);
274+
configure(features, bin, &mut target, edition)?;
267275
result.push(target);
268276
}
269277
return Ok(result);
@@ -289,6 +297,7 @@ fn clean_bins(
289297
}
290298

291299
fn clean_examples(
300+
features: &Features,
292301
toml_examples: Option<&Vec<TomlExampleTarget>>,
293302
package_root: &Path,
294303
edition: Edition,
@@ -324,14 +333,15 @@ fn clean_examples(
324333
path,
325334
toml.required_features.clone(),
326335
);
327-
configure(&toml, &mut target);
336+
configure(features, &toml, &mut target, edition)?;
328337
result.push(target);
329338
}
330339

331340
Ok(result)
332341
}
333342

334343
fn clean_tests(
344+
features: &Features,
335345
toml_tests: Option<&Vec<TomlTestTarget>>,
336346
package_root: &Path,
337347
edition: Edition,
@@ -357,13 +367,14 @@ fn clean_tests(
357367
let mut result = Vec::new();
358368
for (path, toml) in targets {
359369
let mut target = Target::test_target(&toml.name(), path, toml.required_features.clone());
360-
configure(&toml, &mut target);
370+
configure(features, &toml, &mut target, edition)?;
361371
result.push(target);
362372
}
363373
Ok(result)
364374
}
365375

366376
fn clean_benches(
377+
features: &Features,
367378
toml_benches: Option<&Vec<TomlBenchTarget>>,
368379
package_root: &Path,
369380
edition: Edition,
@@ -410,7 +421,7 @@ fn clean_benches(
410421
let mut result = Vec::new();
411422
for (path, toml) in targets {
412423
let mut target = Target::bench_target(&toml.name(), path, toml.required_features.clone());
413-
configure(&toml, &mut target);
424+
configure(features, &toml, &mut target, edition)?;
414425
result.push(target);
415426
}
416427

@@ -682,7 +693,12 @@ fn validate_unique_names(targets: &[TomlTarget], target_kind: &str) -> CargoResu
682693
Ok(())
683694
}
684695

685-
fn configure(toml: &TomlTarget, target: &mut Target) {
696+
fn configure(
697+
features: &Features,
698+
toml: &TomlTarget,
699+
target: &mut Target,
700+
edition: Edition,
701+
) -> CargoResult<()> {
686702
let t2 = target.clone();
687703
target
688704
.set_tested(toml.test.unwrap_or_else(|| t2.tested()))
@@ -694,7 +710,15 @@ fn configure(toml: &TomlTarget, target: &mut Target) {
694710
(None, None) => t2.for_host(),
695711
(Some(true), _) | (_, Some(true)) => true,
696712
(Some(false), _) | (_, Some(false)) => false,
713+
})
714+
.set_edition(match toml.edition.clone() {
715+
None => edition,
716+
Some(s) => {
717+
features.require(Feature::edition()).chain_err(|| "editions are unstable")?;
718+
s.parse().chain_err(|| "failed to parse the `edition` key")?
719+
},
697720
});
721+
Ok(())
698722
}
699723

700724
fn target_path(

src/doc/src/reference/unstable.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,21 @@ cargo +nightly build --out-dir=out -Z unstable-options
187187

188188
You can opt in to a specific Rust Edition for your package with the `edition`
189189
key in `Cargo.toml`. If you don't specify the edition, it will default to
190-
2015. You need to include the appropriate `cargo-features`:
190+
2015. You need to include the appropriate `cargo-features`.
191+
192+
You can also specify `edition` on a per-target level, where it will otherwise
193+
default to the package `edition`.
191194

192195
```toml
193196
cargo-features = ["edition"]
194197

195198
[package]
196199
...
197200
edition = "2018"
201+
202+
[[bin]]
203+
...
204+
edition = "2015"
198205
```
199206

200207

0 commit comments

Comments
 (0)