Skip to content

Commit

Permalink
Rollup merge of rust-lang#37067 - jseyfried:expand_derives_last, r=al…
Browse files Browse the repository at this point in the history
…excrichton

macros: expand `#[derive]`s after other attribute macros and improve intra-`#[derive]` ordering

Fixes serde-rs/serde#577.
cc rust-lang#35900
r? @alexcrichton
  • Loading branch information
alexcrichton committed Oct 12, 2016
2 parents 920f109 + 448d6ad commit 2d71be5
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 7 deletions.
35 changes: 30 additions & 5 deletions src/libsyntax_ext/deriving/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass-fulldeps/macro-crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
1 change: 1 addition & 0 deletions src/test/run-pass-fulldeps/proc-macro/load-two.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extern crate derive_atob;
#[macro_use]
extern crate derive_ctod;

#[derive(Copy, Clone)]
#[derive(AToB)]
struct A;

Expand Down

0 comments on commit 2d71be5

Please sign in to comment.