]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/derive.rs
Auto merge of #57651 - JohnTitor:give-char-type, r=estebank
[rust.git] / src / libsyntax / ext / derive.rs
1 use attr::HasAttrs;
2 use ast;
3 use source_map::{hygiene, ExpnInfo, ExpnFormat};
4 use ext::base::ExtCtxt;
5 use ext::build::AstBuilder;
6 use parse::parser::PathStyle;
7 use symbol::Symbol;
8 use syntax_pos::Span;
9
10 use rustc_data_structures::fx::FxHashSet;
11
12 pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
13     let mut result = Vec::new();
14     attrs.retain(|attr| {
15         if attr.path != "derive" {
16             return true;
17         }
18         if !attr.is_meta_item_list() {
19             cx.span_err(attr.span,
20                         "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`");
21             return false;
22         }
23
24         match attr.parse_list(cx.parse_sess,
25                               |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
26             Ok(ref traits) if traits.is_empty() => {
27                 cx.span_warn(attr.span, "empty trait list in `derive`");
28                 false
29             }
30             Ok(traits) => {
31                 result.extend(traits);
32                 true
33             }
34             Err(mut e) => {
35                 e.emit();
36                 false
37             }
38         }
39     });
40     result
41 }
42
43 pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
44     where T: HasAttrs,
45 {
46     let (mut names, mut pretty_name) = (FxHashSet::default(), "derive(".to_owned());
47     for (i, path) in traits.iter().enumerate() {
48         if i > 0 {
49             pretty_name.push_str(", ");
50         }
51         pretty_name.push_str(&path.to_string());
52         names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
53     }
54     pretty_name.push(')');
55
56     cx.current_expansion.mark.set_expn_info(ExpnInfo {
57         call_site: span,
58         def_site: None,
59         format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
60         allow_internal_unstable: true,
61         allow_internal_unsafe: false,
62         local_inner_macros: false,
63         edition: hygiene::default_edition(),
64     });
65
66     let span = span.with_ctxt(cx.backtrace());
67     item.map_attrs(|mut attrs| {
68         if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
69             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
70             attrs.push(cx.attribute(span, meta));
71         }
72         if names.contains(&Symbol::intern("Copy")) {
73             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
74             attrs.push(cx.attribute(span, meta));
75         }
76         attrs
77     })
78 }