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