1 //! The compiler code necessary to implement the `#[derive]` extensions.
3 use rustc_data_structures::sync::Lrc;
5 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
6 use syntax::ext::build::AstBuilder;
7 use syntax::ext::hygiene::{Mark, SyntaxContext};
9 use syntax::symbol::{Symbol, sym};
12 macro path_local($x:ident) {
13 generic::ty::Path::new_local(stringify!($x))
16 macro pathvec_std($cx:expr, $($rest:ident)::+) {{
17 vec![ $( stringify!($rest) ),+ ]
20 macro path_std($($x:tt)*) {
21 generic::ty::Path::new( pathvec_std!( $($x)* ) )
33 #[path="cmp/partial_eq.rs"]
37 #[path="cmp/partial_ord.rs"]
45 macro_rules! derive_traits {
46 ($( $name:expr => $func:path, )+) => {
47 pub fn is_builtin_trait(name: ast::Name) -> bool {
48 match &*name.as_str() {
54 pub fn register_builtin_derives(resolver: &mut dyn Resolver) {
57 ast::Ident::with_empty_ctxt(Symbol::intern($name)),
58 Lrc::new(SyntaxExtension::BuiltinDerive($func))
66 "Clone" => clone::expand_deriving_clone,
68 "Hash" => hash::expand_deriving_hash,
70 "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
72 "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
74 "PartialEq" => partial_eq::expand_deriving_partial_eq,
75 "Eq" => eq::expand_deriving_eq,
76 "PartialOrd" => partial_ord::expand_deriving_partial_ord,
77 "Ord" => ord::expand_deriving_ord,
79 "Debug" => debug::expand_deriving_debug,
81 "Default" => default::expand_deriving_default,
83 "Send" => bounds::expand_deriving_unsafe_bound,
84 "Sync" => bounds::expand_deriving_unsafe_bound,
85 "Copy" => bounds::expand_deriving_copy,
88 "Encodable" => encodable::expand_deriving_encodable,
89 "Decodable" => decodable::expand_deriving_decodable,
92 #[inline] // because `name` is a compile-time constant
93 fn warn_if_deprecated(ecx: &mut ExtCtxt<'_>, sp: Span, name: &str) {
94 if let Some(replacement) = match name {
95 "Encodable" => Some("RustcEncodable"),
96 "Decodable" => Some("RustcDecodable"),
100 &format!("derive({}) is deprecated in favor of derive({})",
106 /// Construct a name for the inner type parameter that can't collide with any type parameters of
107 /// the item. This is achieved by starting with a base and then concatenating the names of all
108 /// other type parameters.
109 // FIXME(aburka): use real hygiene when that becomes possible
110 fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
111 let mut typaram = String::from(base);
112 if let Annotatable::Item(ref item) = *item {
114 ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
115 ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
116 for param in params {
118 ast::GenericParamKind::Type { .. } => {
119 typaram.push_str(¶m.ident.as_str());
133 /// Constructs an expression that calls an intrinsic
134 fn call_intrinsic(cx: &ExtCtxt<'_>,
137 args: Vec<P<ast::Expr>>)
139 let intrinsic_allowed_via_allow_internal_unstable = cx
140 .current_expansion.mark.expn_info().unwrap()
141 .allow_internal_unstable.map_or(false, |features| features.iter().any(|&s|
142 s == sym::core_intrinsics
144 if intrinsic_allowed_via_allow_internal_unstable {
145 span = span.with_ctxt(cx.backtrace());
146 } else { // Avoid instability errors with user defined curstom derives, cc #36316
147 let mut info = cx.current_expansion.mark.expn_info().unwrap();
148 info.allow_internal_unstable = Some(vec![sym::core_intrinsics].into());
149 let mark = Mark::fresh(Mark::root());
150 mark.set_expn_info(info);
151 span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
153 let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
154 let call = cx.expr_call_global(span, path, args);
156 cx.expr_block(P(ast::Block {
157 stmts: vec![cx.stmt_expr(call)],
158 id: ast::DUMMY_NODE_ID,
159 rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),