From 1a50cc02abe0b65c066579dd9635ca3f1f2ab924 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 31 Aug 2016 21:01:36 -0700 Subject: [PATCH 1/6] Macros 1.1 --- src/cargo/core/manifest.rs | 6 +++++- src/cargo/util/toml.rs | 18 +++++++++++++++++- src/doc/manifest.md | 11 ++++++++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index a0e7450574f..827008b8be4 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -61,6 +61,7 @@ pub enum LibKind { Lib, Rlib, Dylib, + RustcMacro, Other(String), } @@ -70,6 +71,7 @@ impl LibKind { "lib" => LibKind::Lib, "rlib" => LibKind::Rlib, "dylib" => LibKind::Dylib, + "rustc-macro" => LibKind::RustcMacro, s => LibKind::Other(s.to_string()), } } @@ -80,6 +82,7 @@ impl LibKind { LibKind::Lib => "lib", LibKind::Rlib => "rlib", LibKind::Dylib => "dylib", + LibKind::RustcMacro => "rustc-macro", LibKind::Other(ref s) => s, } } @@ -88,7 +91,8 @@ impl LibKind { match *self { LibKind::Lib | LibKind::Rlib | - LibKind::Dylib => true, + LibKind::Dylib | + LibKind::RustcMacro => true, LibKind::Other(..) => false, } } diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 0c138e648bf..811e58b49c4 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -444,6 +444,7 @@ impl TomlManifest { let lib = match self.lib { Some(ref lib) => { try!(lib.validate_library_name()); + try!(lib.validate_crate_type()); Some( TomlTarget { name: lib.name.clone().or(Some(project.name.clone())), @@ -900,6 +901,7 @@ struct TomlTarget { bench: Option, doc: Option, plugin: Option, + rustc_macro: Option, harness: Option, } @@ -928,6 +930,7 @@ impl TomlTarget { bench: None, doc: None, plugin: None, + rustc_macro: None, harness: None, } } @@ -1006,6 +1009,14 @@ impl TomlTarget { None => Err(human("bench target bench.name is required".to_string())) } } + + fn validate_crate_type(&self) -> CargoResult<()> { + if self.plugin == Some(true) && self.rustc_macro == Some(true) { + Err(human("lib.plugin and lib.rustc-macro cannot both be true".to_string())) + } else { + Ok(()) + } + } } impl PathValue { @@ -1040,7 +1051,11 @@ fn normalize(lib: &Option, .set_doctest(toml.doctest.unwrap_or(t2.doctested())) .set_benched(toml.bench.unwrap_or(t2.benched())) .set_harness(toml.harness.unwrap_or(t2.harness())) - .set_for_host(toml.plugin.unwrap_or(t2.for_host())); + .set_for_host(match (toml.plugin, toml.rustc_macro) { + (None, None) => t2.for_host(), + (Some(true), _) | (_, Some(true)) => true, + _ => false, + }); } fn lib_target(dst: &mut Vec, @@ -1053,6 +1068,7 @@ fn normalize(lib: &Option, Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), None => { vec![ if l.plugin == Some(true) {LibKind::Dylib} + else if l.rustc_macro == Some(true) {LibKind::RustcMacro} else {LibKind::Lib} ] } }; diff --git a/src/doc/manifest.md b/src/doc/manifest.md index 675841784d7..086d214d894 100644 --- a/src/doc/manifest.md +++ b/src/doc/manifest.md @@ -508,6 +508,10 @@ doc = true # for Cargo to correctly compile it and make it available for all dependencies. plugin = false +# If the target is meant to be a "macros 1.1" procedural macro, this field must +# be set to true. +rustc-macro = false + # If set to false, `cargo test` will omit the `--test` flag to rustc, which # stops it from generating a test harness. This is useful when the binary being # built manages the test runner itself. @@ -527,9 +531,10 @@ name = "..." crate-type = ["dylib"] # could be `staticlib` as well ``` -The available options are `dylib`, `rlib`, `staticlib`, and `cdylib`. You -should only use this option in a project. Cargo will always compile packages -(dependencies) based on the requirements of the project that includes them. +The available options are `dylib`, `rlib`, `staticlib`, `cdylib`, and +`rustc-macro`. You should only use this option in a project. Cargo will always +compile packages (dependencies) based on the requirements of the project that +includes them. You can read more about the different crate types in the [Rust Reference Manual](https://doc.rust-lang.org/reference.html#linkage) From 5cfc4fb629794ad2b244e9ef840e2fc2fa251845 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Sep 2016 10:29:24 -0700 Subject: [PATCH 2/6] Test for rustc-macro --- tests/rustc-macro.rs | 146 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 tests/rustc-macro.rs diff --git a/tests/rustc-macro.rs b/tests/rustc-macro.rs new file mode 100644 index 00000000000..fe49b359d2d --- /dev/null +++ b/tests/rustc-macro.rs @@ -0,0 +1,146 @@ +extern crate cargotest; +extern crate hamcrest; + +use cargotest::is_nightly; +use cargotest::support::{project, execs}; +use hamcrest::assert_that; + +#[test] +fn noop() { + if !is_nightly() { + return; + } + + let client = project("client") + .file("Cargo.toml", r#" + [package] + name = "client" + version = "0.0.1" + authors = [] + + [dependencies.noop] + path = "../noop" + "#) + .file("src/main.rs", r#" + #![feature(rustc_macro)] + + #[macro_use] + extern crate noop; + + #[derive(Noop)] + struct X; + + fn main() {} + "#); + let noop = project("noop") + .file("Cargo.toml", r#" + [package] + name = "noop" + version = "0.0.1" + authors = [] + + [lib] + rustc-macro = true + "#) + .file("src/lib.rs", r#" + #![feature(rustc_macro, rustc_macro_lib)] + + extern crate rustc_macro; + use rustc_macro::TokenStream; + + #[rustc_macro_derive(Noop)] + pub fn noop(input: TokenStream) -> TokenStream { + input + } + "#); + noop.build(); + + assert_that(client.cargo_process("build"), + execs().with_status(0)); + assert_that(client.cargo("build"), + execs().with_status(0)); +} + +#[test] +fn impl_and_derive() { + if !is_nightly() { + return; + } + + let client = project("client") + .file("Cargo.toml", r#" + [package] + name = "client" + version = "0.0.1" + authors = [] + + [dependencies.transmogrify] + path = "../transmogrify" + "#) + .file("src/main.rs", r#" + #![feature(rustc_macro)] + + #[macro_use] + extern crate transmogrify; + + trait ImplByTransmogrify { + fn impl_by_transmogrify(&self) -> bool; + } + + #[derive(Transmogrify)] + struct X; + + fn main() { + let x = X::new(); + assert!(x.impl_by_transmogrify()); + println!("{:?}", x); + } + "#); + let transmogrify = project("transmogrify") + .file("Cargo.toml", r#" + [package] + name = "transmogrify" + version = "0.0.1" + authors = [] + + [lib] + rustc-macro = true + "#) + .file("src/lib.rs", r#" + #![feature(rustc_macro, rustc_macro_lib)] + + extern crate rustc_macro; + use rustc_macro::TokenStream; + + #[rustc_macro_derive(Transmogrify)] + #[doc(hidden)] + pub fn transmogrify(input: TokenStream) -> TokenStream { + assert_eq!(input.to_string(), "struct X;\n"); + + " + impl X { + fn new() -> Self { + X { success: true } + } + } + + impl ImplByTransmogrify for X { + fn impl_by_transmogrify(&self) -> bool { + true + } + } + + #[derive(Debug)] + struct X { + success: bool, + } + ".parse().unwrap() + } + "#); + transmogrify.build(); + + assert_that(client.cargo_process("build"), + execs().with_status(0)); + assert_that(client.cargo("run"), + execs().with_status(0).with_stdout("X { success: true }")); +} From 5ee95b1775c0aed545b30334fc240c551479d450 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Sep 2016 10:42:23 -0700 Subject: [PATCH 3/6] Test a crate that is both a plugin and a proc macro --- src/cargo/util/toml.rs | 9 +++++++++ tests/rustc-macro.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 811e58b49c4..15e5246315d 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -1011,6 +1011,15 @@ impl TomlTarget { } fn validate_crate_type(&self) -> CargoResult<()> { + // Per the Macros 1.1 RFC: + // + // > Initially if a crate is compiled with the rustc-macro crate type + // > (and possibly others) it will forbid exporting any items in the + // > crate other than those functions tagged #[rustc_macro_derive] and + // > those functions must also be placed at the crate root. + // + // A plugin requires exporting plugin_registrar so a crate cannot be + // both at once. if self.plugin == Some(true) && self.rustc_macro == Some(true) { Err(human("lib.plugin and lib.rustc-macro cannot both be true".to_string())) } else { diff --git a/tests/rustc-macro.rs b/tests/rustc-macro.rs index fe49b359d2d..f3d618b1228 100644 --- a/tests/rustc-macro.rs +++ b/tests/rustc-macro.rs @@ -144,3 +144,44 @@ fn impl_and_derive() { assert_that(client.cargo("run"), execs().with_status(0).with_stdout("X { success: true }")); } + +#[test] +fn plugin_and_rustc_macro() { + if !is_nightly() { + return; + } + + let questionable = project("questionable") + .file("Cargo.toml", r#" + [package] + name = "questionable" + version = "0.0.1" + authors = [] + + [lib] + plugin = true + rustc-macro = true + "#) + .file("src/lib.rs", r#" + #![feature(plugin_registrar, rustc_private)] + #![feature(rustc_macro, rustc_macro_lib)] + + extern crate rustc_plugin; + use rustc_plugin::Registry; + + extern crate rustc_macro; + use rustc_macro::TokenStream; + + #[plugin_registrar] + pub fn plugin_registrar(reg: &mut Registry) {} + + #[rustc_macro_derive(Questionable)] + pub fn questionable(input: TokenStream) -> TokenStream { + input + } + "#); + + let msg = " lib.plugin and lib.rustc-macro cannot both be true"; + assert_that(questionable.cargo_process("build"), + execs().with_status(101).with_stderr_contains(msg)); +} From 5daa4f6875d39d59e384ab8fd1622f4f31c60021 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Sep 2016 14:17:42 -0700 Subject: [PATCH 4/6] Explicitly bind Some(false) --- src/cargo/util/toml.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 15e5246315d..ac94d3a2837 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -1063,7 +1063,7 @@ fn normalize(lib: &Option, .set_for_host(match (toml.plugin, toml.rustc_macro) { (None, None) => t2.for_host(), (Some(true), _) | (_, Some(true)) => true, - _ => false, + (Some(false), _) | (_, Some(false)) => false, }); } From acf34bb5ea8ac733613ec90aed75f5693db3a6f9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 4 Sep 2016 08:25:30 -0700 Subject: [PATCH 5/6] Empty commit to trigger Travis build of rustc-macro From 7ee6f57de1df970c4ea7a46e61339e64fdf12c90 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 6 Sep 2016 10:34:35 -0700 Subject: [PATCH 6/6] Bump rustcversion to pick up rustc-macro support --- src/rustversion.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustversion.txt b/src/rustversion.txt index 8b6746a8608..f96de36a9fd 100644 --- a/src/rustversion.txt +++ b/src/rustversion.txt @@ -1 +1 @@ -2016-07-12 +2016-09-05