]> git.proxmox.com Git - rustc.git/blob - src/libsyntax_ext/deriving/mod.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / libsyntax_ext / deriving / mod.rs
1 //! The compiler code necessary to implement the `#[derive]` extensions.
2
3 use syntax::ast::{self, ItemKind, MetaItem};
4 use syntax_expand::base::{Annotatable, ExtCtxt, MultiItemModifier};
5 use syntax::ptr::P;
6 use syntax::symbol::{Symbol, sym};
7 use syntax_pos::Span;
8
9 macro path_local($x:ident) {
10 generic::ty::Path::new_local(stringify!($x))
11 }
12
13 macro pathvec_std($cx:expr, $($rest:ident)::+) {{
14 vec![ $( stringify!($rest) ),+ ]
15 }}
16
17 macro path_std($($x:tt)*) {
18 generic::ty::Path::new( pathvec_std!( $($x)* ) )
19 }
20
21 pub mod bounds;
22 pub mod clone;
23 pub mod encodable;
24 pub mod decodable;
25 pub mod hash;
26 pub mod debug;
27 pub mod default;
28
29 #[path="cmp/partial_eq.rs"]
30 pub mod partial_eq;
31 #[path="cmp/eq.rs"]
32 pub mod eq;
33 #[path="cmp/partial_ord.rs"]
34 pub mod partial_ord;
35 #[path="cmp/ord.rs"]
36 pub mod ord;
37
38 pub mod generic;
39
40 crate struct BuiltinDerive(
41 crate fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable))
42 );
43
44 impl MultiItemModifier for BuiltinDerive {
45 fn expand(&self,
46 ecx: &mut ExtCtxt<'_>,
47 span: Span,
48 meta_item: &MetaItem,
49 item: Annotatable)
50 -> Vec<Annotatable> {
51 // FIXME: Built-in derives often forget to give spans contexts,
52 // so we are doing it here in a centralized way.
53 let span = ecx.with_def_site_ctxt(span);
54 let mut items = Vec::new();
55 (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
56 items
57 }
58 }
59
60 /// Constructs an expression that calls an intrinsic
61 fn call_intrinsic(cx: &ExtCtxt<'_>,
62 span: Span,
63 intrinsic: &str,
64 args: Vec<P<ast::Expr>>)
65 -> P<ast::Expr> {
66 let span = cx.with_def_site_ctxt(span);
67 let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
68 let call = cx.expr_call_global(span, path, args);
69
70 cx.expr_block(P(ast::Block {
71 stmts: vec![cx.stmt_expr(call)],
72 id: ast::DUMMY_NODE_ID,
73 rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
74 span,
75 }))
76 }
77
78
79 // Injects `impl<...> Structural for ItemType<...> { }`. In particular,
80 // does *not* add `where T: Structural` for parameters `T` in `...`.
81 // (That's the main reason we cannot use TraitDef here.)
82 fn inject_impl_of_structural_trait(cx: &mut ExtCtxt<'_>,
83 span: Span,
84 item: &Annotatable,
85 structural_path: generic::ty::Path<'_>,
86 push: &mut dyn FnMut(Annotatable)) {
87 let item = match *item {
88 Annotatable::Item(ref item) => item,
89 _ => {
90 // Non-Item derive is an error, but it should have been
91 // set earlier; see
92 // libsyntax/ext/expand.rs:MacroExpander::expand()
93 return;
94 }
95 };
96
97 let generics = match item.kind {
98 ItemKind::Struct(_, ref generics) |
99 ItemKind::Enum(_, ref generics) => generics,
100 // Do not inject `impl Structural for Union`. (`PartialEq` does not
101 // support unions, so we will see error downstream.)
102 ItemKind::Union(..) => return,
103 _ => unreachable!(),
104 };
105
106 // Create generics param list for where clauses and impl headers
107 let mut generics = generics.clone();
108
109 // Create the type of `self`.
110 //
111 // in addition, remove defaults from type params (impls cannot have them).
112 let self_params: Vec<_> = generics.params.iter_mut().map(|param| match &mut param.kind {
113 ast::GenericParamKind::Lifetime => {
114 ast::GenericArg::Lifetime(cx.lifetime(span, param.ident))
115 }
116 ast::GenericParamKind::Type { default } => {
117 *default = None;
118 ast::GenericArg::Type(cx.ty_ident(span, param.ident))
119 }
120 ast::GenericParamKind::Const { ty: _ } => {
121 ast::GenericArg::Const(cx.const_ident(span, param.ident))
122 }
123 }).collect();
124
125 let type_ident = item.ident;
126
127 let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
128 let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));
129
130 // It would be nice to also encode constraint `where Self: Eq` (by adding it
131 // onto `generics` cloned above). Unfortunately, that strategy runs afoul of
132 // rust-lang/rust#48214. So we perform that additional check in the compiler
133 // itself, instead of encoding it here.
134
135 // Keep the lint and stability attributes of the original item, to control
136 // how the generated implementation is linted.
137 let mut attrs = Vec::new();
138 attrs.extend(item.attrs
139 .iter()
140 .filter(|a| {
141 [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
142 .contains(&a.name_or_empty())
143 })
144 .cloned());
145
146 let newitem = cx.item(span,
147 ast::Ident::invalid(),
148 attrs,
149 ItemKind::Impl(ast::Unsafety::Normal,
150 ast::ImplPolarity::Positive,
151 ast::Defaultness::Final,
152 generics,
153 Some(trait_ref),
154 self_type,
155 Vec::new()));
156
157 push(Annotatable::Item(newitem));
158 }