1 // Copyright 2012-2015 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.
11 //! The compiler code necessary to implement the `#[derive]` extensions.
13 use rustc_data_structures::sync::Lrc;
15 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
16 use syntax::ext::build::AstBuilder;
17 use syntax::ext::hygiene::{Mark, SyntaxContext};
19 use syntax::symbol::Symbol;
22 macro_rules! span_err_if_not_stage0 {
23 ($cx:expr, $sp:expr, $code:ident, $text:tt) => {
25 span_err!($cx, $sp, $code, $text)
28 $cx.span_err($sp, $text)
33 macro path_local($x:ident) {
34 generic::ty::Path::new_local(stringify!($x))
37 macro pathvec_std($cx:expr, $($rest:ident)::+) {{
38 vec![ $( stringify!($rest) ),+ ]
41 macro path_std($($x:tt)*) {
42 generic::ty::Path::new( pathvec_std!( $($x)* ) )
54 #[path="cmp/partial_eq.rs"]
58 #[path="cmp/partial_ord.rs"]
66 macro_rules! derive_traits {
67 ($( $name:expr => $func:path, )+) => {
68 pub fn is_builtin_trait(name: ast::Name) -> bool {
69 match &*name.as_str() {
75 pub fn register_builtin_derives(resolver: &mut dyn Resolver) {
78 ast::Ident::with_empty_ctxt(Symbol::intern($name)),
79 Lrc::new(SyntaxExtension::BuiltinDerive($func))
87 "Clone" => clone::expand_deriving_clone,
89 "Hash" => hash::expand_deriving_hash,
91 "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
93 "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
95 "PartialEq" => partial_eq::expand_deriving_partial_eq,
96 "Eq" => eq::expand_deriving_eq,
97 "PartialOrd" => partial_ord::expand_deriving_partial_ord,
98 "Ord" => ord::expand_deriving_ord,
100 "Debug" => debug::expand_deriving_debug,
102 "Default" => default::expand_deriving_default,
104 "Send" => bounds::expand_deriving_unsafe_bound,
105 "Sync" => bounds::expand_deriving_unsafe_bound,
106 "Copy" => bounds::expand_deriving_copy,
109 "Encodable" => encodable::expand_deriving_encodable,
110 "Decodable" => decodable::expand_deriving_decodable,
113 #[inline] // because `name` is a compile-time constant
114 fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
115 if let Some(replacement) = match name {
116 "Encodable" => Some("RustcEncodable"),
117 "Decodable" => Some("RustcDecodable"),
121 &format!("derive({}) is deprecated in favor of derive({})",
127 /// Construct a name for the inner type parameter that can't collide with any type parameters of
128 /// the item. This is achieved by starting with a base and then concatenating the names of all
129 /// other type parameters.
130 // FIXME(aburka): use real hygiene when that becomes possible
131 fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
132 let mut typaram = String::from(base);
133 if let Annotatable::Item(ref item) = *item {
135 ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
136 ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
137 for param in params {
139 ast::GenericParamKind::Type { .. } => {
140 typaram.push_str(¶m.ident.as_str());
154 /// Constructs an expression that calls an intrinsic
155 fn call_intrinsic(cx: &ExtCtxt,
158 args: Vec<P<ast::Expr>>)
160 if cx.current_expansion.mark.expn_info().unwrap().allow_internal_unstable {
161 span = span.with_ctxt(cx.backtrace());
162 } else { // Avoid instability errors with user defined curstom derives, cc #36316
163 let mut info = cx.current_expansion.mark.expn_info().unwrap();
164 info.allow_internal_unstable = true;
165 let mark = Mark::fresh(Mark::root());
166 mark.set_expn_info(info);
167 span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
169 let path = cx.std_path(&["intrinsics", intrinsic]);
170 let call = cx.expr_call_global(span, path, args);
172 cx.expr_block(P(ast::Block {
173 stmts: vec![cx.stmt_expr(call)],
174 id: ast::DUMMY_NODE_ID,
175 rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),