From 442f6297bfcdd2a313732b2250ffda2ed974d181 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 3 Jun 2020 07:38:21 -0700 Subject: [PATCH] Fix an accidental raw access of field The manifest has a few different ways of specifying whether a crate is a procedural macro, and there's a `TomlTarget::proc_macro()` method to unify these various lines. Unfortunately though we had a bug where one location forgot to call the method and read the raw field! This led to surprising behavior where the different ways to specify a proc macro would have subtly different changes in behavior. The fix here in this PR is to ensure that we access the property always via the method. Closes #8315 --- src/cargo/util/toml/mod.rs | 6 +-- src/cargo/util/toml/targets.rs | 2 +- tests/testsuite/proc_macro.rs | 69 ++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 6367a12e410..b1688b85744 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1767,9 +1767,9 @@ struct TomlTarget { doc: Option, plugin: Option, #[serde(rename = "proc-macro")] - proc_macro: Option, + proc_macro_raw: Option, #[serde(rename = "proc_macro")] - proc_macro2: Option, + proc_macro_raw2: Option, harness: Option, #[serde(rename = "required-features")] required_features: Option>, @@ -1824,7 +1824,7 @@ impl TomlTarget { } fn proc_macro(&self) -> Option { - self.proc_macro.or(self.proc_macro2).or_else(|| { + self.proc_macro_raw.or(self.proc_macro_raw2).or_else(|| { if let Some(types) = self.crate_types() { if types.contains(&"proc-macro".to_string()) { return Some(true); diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index b383adee102..a711acd556b 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -774,7 +774,7 @@ fn configure(features: &Features, toml: &TomlTarget, target: &mut Target) -> Car .set_doctest(toml.doctest.unwrap_or_else(|| t2.doctested())) .set_benched(toml.bench.unwrap_or_else(|| t2.benched())) .set_harness(toml.harness.unwrap_or_else(|| t2.harness())) - .set_proc_macro(toml.proc_macro.unwrap_or_else(|| t2.proc_macro())) + .set_proc_macro(toml.proc_macro().unwrap_or_else(|| t2.proc_macro())) .set_for_host(match (toml.plugin, toml.proc_macro()) { (None, None) => t2.for_host(), (Some(true), _) | (_, Some(true)) => true, diff --git a/tests/testsuite/proc_macro.rs b/tests/testsuite/proc_macro.rs index be5d024e12d..f80c3eb1987 100644 --- a/tests/testsuite/proc_macro.rs +++ b/tests/testsuite/proc_macro.rs @@ -470,3 +470,72 @@ fn proc_macro_extern_prelude() { p.cargo("test").run(); p.cargo("doc").run(); } + +#[cargo_test] +fn proc_macro_built_once() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ['a', 'b'] + "#, + ) + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + + [build-dependencies] + the-macro = { path = '../the-macro' } + "#, + ) + .file("a/build.rs", "fn main() {}") + .file("a/src/main.rs", "fn main() {}") + .file( + "b/Cargo.toml", + r#" + [package] + name = "b" + version = "0.1.0" + + [dependencies] + the-macro = { path = '../the-macro', features = ['a'] } + "#, + ) + .file("b/src/main.rs", "fn main() {}") + .file( + "the-macro/Cargo.toml", + r#" + [package] + name = "the-macro" + version = "0.1.0" + + [lib] + proc_macro = true + + [features] + a = [] + "#, + ) + .file("the-macro/src/lib.rs", "") + .build(); + p.cargo("build -Zfeatures=all --verbose") + .masquerade_as_nightly_cargo() + .with_stderr_unordered( + "\ +[COMPILING] the-macro [..] +[RUNNING] `rustc --crate-name the_macro [..]` +[COMPILING] b [..] +[RUNNING] `rustc --crate-name b [..]` +[COMPILING] a [..] +[RUNNING] `rustc --crate-name build_script_build [..]` +[RUNNING] `[..]build[..]script[..]build[..]` +[RUNNING] `rustc --crate-name a [..]` +[FINISHED] [..] +", + ) + .run(); +}