]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/mod.rs
Rollup merge of #60667 - oli-obk:raw_from_raw_parts, r=sfackler
[rust.git] / src / libsyntax_ext / deriving / mod.rs
1 //! The compiler code necessary to implement the `#[derive]` extensions.
2
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;
9 use syntax::ptr::P;
10 use syntax::symbol::{Symbol, sym};
11 use syntax_pos::Span;
12
13 macro path_local($x:ident) {
14     generic::ty::Path::new_local(stringify!($x))
15 }
16
17 macro pathvec_std($cx:expr, $($rest:ident)::+) {{
18     vec![ $( stringify!($rest) ),+ ]
19 }}
20
21 macro path_std($($x:tt)*) {
22     generic::ty::Path::new( pathvec_std!( $($x)* ) )
23 }
24
25 pub mod bounds;
26 pub mod clone;
27 pub mod encodable;
28 pub mod decodable;
29 pub mod hash;
30 pub mod debug;
31 pub mod default;
32 pub mod custom;
33
34 #[path="cmp/partial_eq.rs"]
35 pub mod partial_eq;
36 #[path="cmp/eq.rs"]
37 pub mod eq;
38 #[path="cmp/partial_ord.rs"]
39 pub mod partial_ord;
40 #[path="cmp/ord.rs"]
41 pub mod ord;
42
43 pub mod generic;
44
45 struct BuiltinDerive(
46     fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable))
47 );
48
49 impl MultiItemModifier for BuiltinDerive {
50     fn expand(&self,
51               ecx: &mut ExtCtxt<'_>,
52               span: Span,
53               meta_item: &MetaItem,
54               item: Annotatable)
55               -> Vec<Annotatable> {
56         let mut items = Vec::new();
57         (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
58         items
59     }
60 }
61
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() {
66                 $( $name )|+ => true,
67                 _ => false,
68             }
69         }
70
71         pub fn register_builtin_derives(resolver: &mut dyn Resolver, edition: Edition) {
72             let allow_internal_unstable = Some([
73                 sym::core_intrinsics,
74                 sym::rustc_attrs,
75                 Symbol::intern("derive_clone_copy"),
76                 Symbol::intern("derive_eq"),
77                 Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
78             ][..].into());
79
80             $(
81                 resolver.add_builtin(
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))),
87                             edition,
88                         )
89                     }),
90                 );
91             )*
92         }
93     }
94 }
95
96 derive_traits! {
97     "Clone" => clone::expand_deriving_clone,
98
99     "Hash" => hash::expand_deriving_hash,
100
101     "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
102
103     "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
104
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,
109
110     "Debug" => debug::expand_deriving_debug,
111
112     "Default" => default::expand_deriving_default,
113
114     "Send" => bounds::expand_deriving_unsafe_bound,
115     "Sync" => bounds::expand_deriving_unsafe_bound,
116     "Copy" => bounds::expand_deriving_copy,
117
118     // deprecated
119     "Encodable" => encodable::expand_deriving_encodable,
120     "Decodable" => decodable::expand_deriving_decodable,
121 }
122
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"),
128         _ => None,
129     } {
130         ecx.span_warn(sp,
131                       &format!("derive({}) is deprecated in favor of derive({})",
132                                name,
133                                replacement));
134     }
135 }
136
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 {
144         match item.node {
145             ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
146             ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
147                 for param in params {
148                     match param.kind {
149                         ast::GenericParamKind::Type { .. } => {
150                             typaram.push_str(&param.ident.as_str());
151                         }
152                         _ => {}
153                     }
154                 }
155             }
156
157             _ => {}
158         }
159     }
160
161     typaram
162 }
163
164 /// Constructs an expression that calls an intrinsic
165 fn call_intrinsic(cx: &ExtCtxt<'_>,
166                   span: Span,
167                   intrinsic: &str,
168                   args: Vec<P<ast::Expr>>)
169                   -> 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);
173
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),
178         span,
179     }))
180 }