2017-02-01 04:33:09 -06:00
|
|
|
// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2017-02-02 01:01:15 -06:00
|
|
|
use attr::HasAttrs;
|
|
|
|
use {ast, codemap};
|
|
|
|
use ext::base::ExtCtxt;
|
2017-02-01 04:33:09 -06:00
|
|
|
use ext::build::AstBuilder;
|
|
|
|
use symbol::Symbol;
|
|
|
|
use syntax_pos::Span;
|
|
|
|
|
2017-02-02 01:01:15 -06:00
|
|
|
pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<(Symbol, Span)> {
|
|
|
|
let mut result = Vec::new();
|
|
|
|
attrs.retain(|attr| {
|
2017-03-03 03:23:59 -06:00
|
|
|
if attr.path != "derive" {
|
2017-02-02 01:01:15 -06:00
|
|
|
return true;
|
2017-02-01 04:33:09 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if attr.value_str().is_some() {
|
|
|
|
cx.span_err(attr.span, "unexpected value in `derive`");
|
2017-02-02 01:01:15 -06:00
|
|
|
return false;
|
2017-02-01 04:33:09 -06:00
|
|
|
}
|
|
|
|
|
2017-03-03 03:23:59 -06:00
|
|
|
let traits = attr.meta_item_list().unwrap_or_else(Vec::new);
|
2017-02-01 04:33:09 -06:00
|
|
|
if traits.is_empty() {
|
|
|
|
cx.span_warn(attr.span, "empty trait list in `derive`");
|
2017-02-02 01:01:15 -06:00
|
|
|
return false;
|
2017-02-01 04:33:09 -06:00
|
|
|
}
|
2017-02-02 01:01:15 -06:00
|
|
|
|
2017-02-01 04:33:09 -06:00
|
|
|
for titem in traits {
|
|
|
|
if titem.word().is_none() {
|
|
|
|
cx.span_err(titem.span, "malformed `derive` entry");
|
2017-02-02 01:01:15 -06:00
|
|
|
return false;
|
2017-02-01 04:33:09 -06:00
|
|
|
}
|
2017-02-02 01:01:15 -06:00
|
|
|
result.push((titem.name().unwrap(), titem.span));
|
2017-02-01 04:33:09 -06:00
|
|
|
}
|
|
|
|
|
2017-02-02 01:01:15 -06:00
|
|
|
true
|
|
|
|
});
|
|
|
|
result
|
2017-02-01 04:33:09 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
|
|
|
|
Span {
|
|
|
|
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
|
|
|
|
call_site: span,
|
|
|
|
callee: codemap::NameAndSpan {
|
|
|
|
format: codemap::MacroAttribute(Symbol::intern(attr_name)),
|
|
|
|
span: Some(span),
|
|
|
|
allow_internal_unstable: true,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
..span
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-02 01:01:15 -06:00
|
|
|
pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[(Symbol, Span)], item: T) -> T {
|
|
|
|
let span = match traits.get(0) {
|
|
|
|
Some(&(_, span)) => span,
|
|
|
|
None => return item,
|
|
|
|
};
|
|
|
|
|
|
|
|
item.map_attrs(|mut attrs| {
|
|
|
|
if traits.iter().any(|&(name, _)| name == "PartialEq") &&
|
|
|
|
traits.iter().any(|&(name, _)| name == "Eq") {
|
|
|
|
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
|
|
|
|
let meta = cx.meta_word(span, Symbol::intern("structural_match"));
|
|
|
|
attrs.push(cx.attribute(span, meta));
|
|
|
|
}
|
|
|
|
if traits.iter().any(|&(name, _)| name == "Copy") &&
|
|
|
|
traits.iter().any(|&(name, _)| name == "Clone") {
|
|
|
|
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
|
|
|
|
let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
|
|
|
|
attrs.push(cx.attribute(span, meta));
|
|
|
|
}
|
|
|
|
attrs
|
2017-02-01 04:33:09 -06:00
|
|
|
})
|
|
|
|
}
|