]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/derive.rs
Rollup merge of #58275 - RalfJung:miri-test-libcore, r=Mark-Simulacrum
[rust.git] / src / libsyntax / ext / derive.rs
1 use crate::attr::HasAttrs;
2 use crate::ast;
3 use crate::source_map::{hygiene, ExpnInfo, ExpnFormat};
4 use crate::ext::base::ExtCtxt;
5 use crate::ext::build::AstBuilder;
6 use crate::parse::parser::PathStyle;
7 use crate::symbol::Symbol;
8
9 use syntax_pos::Span;
10
11 use rustc_data_structures::fx::FxHashSet;
12
13 pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
14     let mut result = Vec::new();
15     attrs.retain(|attr| {
16         if attr.path != "derive" {
17             return true;
18         }
19         if !attr.is_meta_item_list() {
20             cx.span_err(attr.span,
21                         "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`");
22             return false;
23         }
24
25         match attr.parse_list(cx.parse_sess,
26                               |parser| parser.parse_path_allowing_meta(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 pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T)
45     where T: HasAttrs,
46 {
47     let (mut names, mut pretty_name) = (FxHashSet::default(), "derive(".to_owned());
48     for (i, path) in traits.iter().enumerate() {
49         if i > 0 {
50             pretty_name.push_str(", ");
51         }
52         pretty_name.push_str(&path.to_string());
53         names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
54     }
55     pretty_name.push(')');
56
57     cx.current_expansion.mark.set_expn_info(ExpnInfo {
58         call_site: span,
59         def_site: None,
60         format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
61         allow_internal_unstable: true,
62         allow_internal_unsafe: false,
63         local_inner_macros: false,
64         edition: hygiene::default_edition(),
65     });
66
67     let span = span.with_ctxt(cx.backtrace());
68     item.visit_attrs(|attrs| {
69         if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
70             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
71             attrs.push(cx.attribute(span, meta));
72         }
73         if names.contains(&Symbol::intern("Copy")) {
74             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
75             attrs.push(cx.attribute(span, meta));
76         }
77     });
78 }