1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use rustc_macro::{TokenStream, __internal};
14 use syntax::ast::{self, ItemKind};
15 use syntax::codemap::Span;
16 use syntax::ext::base::*;
17 use syntax::fold::{self, Folder};
18 use errors::FatalError;
20 pub struct CustomDerive {
21 inner: fn(TokenStream) -> TokenStream,
25 pub fn new(inner: fn(TokenStream) -> TokenStream) -> CustomDerive {
26 CustomDerive { inner: inner }
30 impl MultiItemModifier for CustomDerive {
34 _meta_item: &ast::MetaItem,
37 let item = match item {
38 Annotatable::Item(item) => item,
39 Annotatable::ImplItem(_) |
40 Annotatable::TraitItem(_) => {
41 ecx.span_err(span, "custom derive attributes may only be \
42 applied to struct/enum items");
47 ItemKind::Struct(..) |
48 ItemKind::Enum(..) => {}
50 ecx.span_err(span, "custom derive attributes may only be \
51 applied to struct/enum items");
56 let input_span = item.span;
57 let input = __internal::new_token_stream(item);
58 let res = __internal::set_parse_sess(&ecx.parse_sess, || {
59 let inner = self.inner;
60 panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input)))
62 let item = match res {
63 Ok(stream) => __internal::token_stream_items(stream),
65 let msg = "custom derive attribute panicked";
66 let mut err = ecx.struct_span_fatal(span, msg);
67 if let Some(s) = e.downcast_ref::<String>() {
68 err.help(&format!("message: {}", s));
70 if let Some(s) = e.downcast_ref::<&'static str>() {
71 err.help(&format!("message: {}", s));
79 // Right now we have no knowledge of spans at all in custom derive
80 // macros, everything is just parsed as a string. Reassign all spans to
81 // the input `item` for better errors here.
82 item.into_iter().flat_map(|item| {
83 ChangeSpan { span: input_span }.fold_item(item)
84 }).map(Annotatable::Item).collect()
88 struct ChangeSpan { span: Span }
90 impl Folder for ChangeSpan {
91 fn new_span(&mut self, _sp: Span) -> Span {
95 fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
96 fold::noop_fold_mac(mac, self)