]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/derive.rs
Rollup merge of #40521 - TimNN:panic-free-shift, r=alexcrichton
[rust.git] / src / libsyntax / ext / derive.rs
1 // Copyright 2012-2017 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.
4 //
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.
10
11 use attr::HasAttrs;
12 use {ast, codemap};
13 use ext::base::ExtCtxt;
14 use ext::build::AstBuilder;
15 use parse::parser::PathStyle;
16 use symbol::Symbol;
17 use syntax_pos::Span;
18
19 pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
20     let mut result = Vec::new();
21     attrs.retain(|attr| {
22         if attr.path != "derive" {
23             return true;
24         }
25
26         match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
27             Ok(ref traits) if traits.is_empty() => {
28                 cx.span_warn(attr.span, "empty trait list in `derive`");
29                 false
30             }
31             Ok(traits) => {
32                 result.extend(traits);
33                 true
34             }
35             Err(mut e) => {
36                 e.emit();
37                 false
38             }
39         }
40     });
41     result
42 }
43
44 fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
45     Span {
46         expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
47             call_site: span,
48             callee: codemap::NameAndSpan {
49                 format: codemap::MacroAttribute(Symbol::intern(attr_name)),
50                 span: Some(span),
51                 allow_internal_unstable: true,
52             },
53         }),
54         ..span
55     }
56 }
57
58 pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T {
59     let span = match traits.get(0) {
60         Some(path) => path.span,
61         None => return item,
62     };
63
64     item.map_attrs(|mut attrs| {
65         if traits.iter().any(|path| *path == "PartialEq") &&
66            traits.iter().any(|path| *path == "Eq") {
67             let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
68             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
69             attrs.push(cx.attribute(span, meta));
70         }
71         if traits.iter().any(|path| *path == "Copy") &&
72            traits.iter().any(|path| *path == "Clone") {
73             let span = allow_unstable(cx, span, "derive(Copy, Clone)");
74             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
75             attrs.push(cx.attribute(span, meta));
76         }
77         attrs
78     })
79 }