1 //! The compiler code necessary to implement the `#[derive]` extensions.
3 use rustc_data_structures::sync::Lrc;
4 use syntax::ast::{self, MetaItem};
5 use syntax::edition::Edition;
6 use syntax::ext::base::{Annotatable, ExtCtxt, Resolver, MultiItemModifier};
7 use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
8 use syntax::ext::build::AstBuilder;
10 use syntax::symbol::{Symbol, sym};
13 macro path_local($x:ident) {
14 generic::ty::Path::new_local(stringify!($x))
17 macro pathvec_std($cx:expr, $($rest:ident)::+) {{
18 vec![ $( stringify!($rest) ),+ ]
21 macro path_std($($x:tt)*) {
22 generic::ty::Path::new( pathvec_std!( $($x)* ) )
34 #[path="cmp/partial_eq.rs"]
38 #[path="cmp/partial_ord.rs"]
46 fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable))
49 impl MultiItemModifier for BuiltinDerive {
51 ecx: &mut ExtCtxt<'_>,
56 let mut items = Vec::new();
57 (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
62 macro_rules! derive_traits {
63 ($( $name:expr => $func:path, )+) => {
64 pub fn is_builtin_trait(name: ast::Name) -> bool {
65 match &*name.as_str() {
71 pub fn register_builtin_derives(resolver: &mut dyn Resolver, edition: Edition) {
72 let allow_internal_unstable = Some([
75 Symbol::intern("derive_clone_copy"),
76 Symbol::intern("derive_eq"),
77 Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
82 ast::Ident::with_empty_ctxt(Symbol::intern($name)),
83 Lrc::new(SyntaxExtension {
84 allow_internal_unstable: allow_internal_unstable.clone(),
85 ..SyntaxExtension::default(
86 SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($func))),
97 "Clone" => clone::expand_deriving_clone,
99 "Hash" => hash::expand_deriving_hash,
101 "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
103 "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
105 "PartialEq" => partial_eq::expand_deriving_partial_eq,
106 "Eq" => eq::expand_deriving_eq,
107 "PartialOrd" => partial_ord::expand_deriving_partial_ord,
108 "Ord" => ord::expand_deriving_ord,
110 "Debug" => debug::expand_deriving_debug,
112 "Default" => default::expand_deriving_default,
114 "Send" => bounds::expand_deriving_unsafe_bound,
115 "Sync" => bounds::expand_deriving_unsafe_bound,
116 "Copy" => bounds::expand_deriving_copy,
119 "Encodable" => encodable::expand_deriving_encodable,
120 "Decodable" => decodable::expand_deriving_decodable,
123 #[inline] // because `name` is a compile-time constant
124 fn warn_if_deprecated(ecx: &mut ExtCtxt<'_>, sp: Span, name: &str) {
125 if let Some(replacement) = match name {
126 "Encodable" => Some("RustcEncodable"),
127 "Decodable" => Some("RustcDecodable"),
131 &format!("derive({}) is deprecated in favor of derive({})",
137 /// Construct a name for the inner type parameter that can't collide with any type parameters of
138 /// the item. This is achieved by starting with a base and then concatenating the names of all
139 /// other type parameters.
140 // FIXME(aburka): use real hygiene when that becomes possible
141 fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
142 let mut typaram = String::from(base);
143 if let Annotatable::Item(ref item) = *item {
145 ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
146 ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
147 for param in params {
149 ast::GenericParamKind::Type { .. } => {
150 typaram.push_str(¶m.ident.as_str());
164 /// Constructs an expression that calls an intrinsic
165 fn call_intrinsic(cx: &ExtCtxt<'_>,
168 args: Vec<P<ast::Expr>>)
170 let span = span.with_ctxt(cx.backtrace());
171 let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
172 let call = cx.expr_call_global(span, path, args);
174 cx.expr_block(P(ast::Block {
175 stmts: vec![cx.stmt_expr(call)],
176 id: ast::DUMMY_NODE_ID,
177 rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),