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
This commit is contained in:
commit
2d71be5780
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ extern crate derive_atob;
|
||||
#[macro_use]
|
||||
extern crate derive_ctod;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(AToB)]
|
||||
struct A;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user