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