Skip to content

Commit 3cf07a8

Browse files
author
Jonathan Turner
authored
Rollup merge of #37067 - jseyfried:expand_derives_last, r=alexcrichton
macros: expand `#[derive]`s after other attribute macros and improve intra-`#[derive]` ordering Fixes serde-rs/serde#577. cc #35900 r? @alexcrichton
2 parents a44bb87 + 448d6ad commit 3cf07a8

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed

src/libsyntax_ext/deriving/mod.rs

+30-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//! The compiler code necessary to implement the `#[derive]` extensions.
1212
1313
use syntax::ast::{self, MetaItem};
14+
use syntax::attr::HasAttrs;
1415
use syntax::ext::base::{Annotatable, ExtCtxt};
1516
use syntax::ext::build::AstBuilder;
1617
use syntax::feature_gate;
@@ -104,13 +105,37 @@ pub fn expand_derive(cx: &mut ExtCtxt,
104105
}
105106
};
106107

107-
if mitem.value_str().is_some() {
108-
cx.span_err(mitem.span, "unexpected value in `derive`");
108+
let mut derive_attrs = Vec::new();
109+
item = item.map_attrs(|attrs| {
110+
let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive");
111+
derive_attrs = partition.0;
112+
partition.1
113+
});
114+
115+
// Expand `#[derive]`s after other attribute macro invocations.
116+
if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
117+
return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
118+
attrs.push(cx.attribute(span, P(mitem.clone())));
119+
attrs.extend(derive_attrs);
120+
attrs
121+
}))];
109122
}
110123

111-
let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
112-
if traits.is_empty() {
113-
cx.span_warn(mitem.span, "empty trait list in `derive`");
124+
let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
125+
if mitem.value_str().is_some() {
126+
cx.span_err(mitem.span, "unexpected value in `derive`");
127+
}
128+
129+
let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
130+
if traits.is_empty() {
131+
cx.span_warn(mitem.span, "empty trait list in `derive`");
132+
}
133+
traits
134+
};
135+
136+
let mut traits = get_traits(mitem, cx);
137+
for derive_attr in derive_attrs {
138+
traits.extend(get_traits(&derive_attr.node.value, cx));
114139
}
115140

116141
// First, weed out malformed #[derive]

src/test/run-pass-fulldeps/macro-crate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
#[macro_use] #[no_link]
1818
extern crate macro_crate_test;
1919

20-
#[into_multi_foo]
2120
#[derive(PartialEq, Clone, Debug)]
21+
#[into_multi_foo]
2222
fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
2323

2424
// Check that the `#[into_multi_foo]`-generated `foo2` is configured away

src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ use proc_macro::TokenStream;
2121
#[proc_macro_derive(AToB)]
2222
pub fn derive(input: TokenStream) -> TokenStream {
2323
let input = input.to_string();
24-
assert_eq!(input, "struct A;\n");
24+
assert_eq!(input, "#[derive(Copy, Clone)]\nstruct A;\n");
2525
"struct B;".parse().unwrap()
2626
}

src/test/run-pass-fulldeps/proc-macro/load-two.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern crate derive_atob;
1818
#[macro_use]
1919
extern crate derive_ctod;
2020

21+
#[derive(Copy, Clone)]
2122
#[derive(AToB)]
2223
struct A;
2324

0 commit comments

Comments
 (0)