about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2016-10-12 10:15:28 -0700
committerAlex Crichton <alex@alexcrichton.com>2016-10-12 14:07:56 -0700
commit2d71be5780f2c7548956625d2261d39798f3ce83 (patch)
treedcfb0eddf7b9afb278dfb50db2dcecb213fcf58f
parent920f10950ab30dd85da5136a25cf3a9794410e9b (diff)
parent448d6ad72e1f68dfe1ede8caa492fd79af9d9303 (diff)
downloadrust-2d71be5780f2c7548956625d2261d39798f3ce83.tar.gz
rust-2d71be5780f2c7548956625d2261d39798f3ce83.zip
Rollup merge of #37067 - jseyfried:expand_derives_last, r=alexcrichton
macros: expand `#[derive]`s after other attribute macros and improve intra-`#[derive]` ordering

Fixes https://github.com/serde-rs/serde/issues/577.
cc #35900
r? @alexcrichton
-rw-r--r--src/libsyntax_ext/deriving/mod.rs35
-rw-r--r--src/test/run-pass-fulldeps/macro-crate.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/load-two.rs1
4 files changed, 33 insertions, 7 deletions
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index fdb10a2beb2..9f99919c895 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -11,6 +11,7 @@
 //! The compiler code necessary to implement the `#[derive]` extensions.
 
 use syntax::ast::{self, MetaItem};
+use syntax::attr::HasAttrs;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
 use syntax::feature_gate;
@@ -104,13 +105,37 @@ pub fn expand_derive(cx: &mut ExtCtxt,
         }
     };
 
-    if mitem.value_str().is_some() {
-        cx.span_err(mitem.span, "unexpected value in `derive`");
+    let mut derive_attrs = Vec::new();
+    item = item.map_attrs(|attrs| {
+        let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive");
+        derive_attrs = partition.0;
+        partition.1
+    });
+
+    // Expand `#[derive]`s after other attribute macro invocations.
+    if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
+        return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
+            attrs.push(cx.attribute(span, P(mitem.clone())));
+            attrs.extend(derive_attrs);
+            attrs
+        }))];
     }
 
-    let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
-    if traits.is_empty() {
-        cx.span_warn(mitem.span, "empty trait list in `derive`");
+    let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
+        if mitem.value_str().is_some() {
+            cx.span_err(mitem.span, "unexpected value in `derive`");
+        }
+
+        let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
+        if traits.is_empty() {
+            cx.span_warn(mitem.span, "empty trait list in `derive`");
+        }
+        traits
+    };
+
+    let mut traits = get_traits(mitem, cx);
+    for derive_attr in derive_attrs {
+        traits.extend(get_traits(&derive_attr.node.value, cx));
     }
 
     // First, weed out malformed #[derive]
diff --git a/src/test/run-pass-fulldeps/macro-crate.rs b/src/test/run-pass-fulldeps/macro-crate.rs
index fe2317aabea..9b2e36c8cea 100644
--- a/src/test/run-pass-fulldeps/macro-crate.rs
+++ b/src/test/run-pass-fulldeps/macro-crate.rs
@@ -17,8 +17,8 @@
 #[macro_use] #[no_link]
 extern crate macro_crate_test;
 
-#[into_multi_foo]
 #[derive(PartialEq, Clone, Debug)]
+#[into_multi_foo]
 fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
 
 // Check that the `#[into_multi_foo]`-generated `foo2` is configured away
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs
index b9e31fc3329..a942adc4c80 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs
@@ -21,6 +21,6 @@ use proc_macro::TokenStream;
 #[proc_macro_derive(AToB)]
 pub fn derive(input: TokenStream) -> TokenStream {
     let input = input.to_string();
-    assert_eq!(input, "struct A;\n");
+    assert_eq!(input, "#[derive(Copy, Clone)]\nstruct A;\n");
     "struct B;".parse().unwrap()
 }
diff --git a/src/test/run-pass-fulldeps/proc-macro/load-two.rs b/src/test/run-pass-fulldeps/proc-macro/load-two.rs
index 56f9768764c..431c8c59027 100644
--- a/src/test/run-pass-fulldeps/proc-macro/load-two.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/load-two.rs
@@ -18,6 +18,7 @@ extern crate derive_atob;
 #[macro_use]
 extern crate derive_ctod;
 
+#[derive(Copy, Clone)]
 #[derive(AToB)]
 struct A;