]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_builtin_macros/src/deriving/mod.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / deriving / mod.rs
CommitLineData
1a4d82fc 1//! The compiler code necessary to implement the `#[derive]` extensions.
223e47cc 2
3dfed10e 3use rustc_ast as ast;
74b04a01 4use rustc_ast::ptr::P;
064997fb 5use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem};
ba9703b0 6use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
f9f354fc 7use rustc_span::symbol::{sym, Ident, Symbol};
dfeec247 8use rustc_span::Span;
223e47cc 9
ff7c6d11 10macro path_local($x:ident) {
3dfed10e 11 generic::ty::Path::new_local(sym::$x)
85aaf69f
SL
12}
13
3dfed10e
XL
14macro pathvec_std($($rest:ident)::+) {{
15 vec![ $( sym::$rest ),+ ]
ff7c6d11 16}}
85aaf69f 17
ff7c6d11
XL
18macro path_std($($x:tt)*) {
19 generic::ty::Path::new( pathvec_std!( $($x)* ) )
85aaf69f
SL
20}
21
1a4d82fc 22pub mod bounds;
223e47cc 23pub mod clone;
b039eaaf 24pub mod debug;
dfeec247 25pub mod decodable;
1a4d82fc 26pub mod default;
dfeec247
XL
27pub mod encodable;
28pub mod hash;
970d7e83 29
dfeec247 30#[path = "cmp/eq.rs"]
970d7e83 31pub mod eq;
dfeec247 32#[path = "cmp/ord.rs"]
970d7e83 33pub mod ord;
dfeec247
XL
34#[path = "cmp/partial_eq.rs"]
35pub mod partial_eq;
36#[path = "cmp/partial_ord.rs"]
37pub mod partial_ord;
223e47cc 38
970d7e83
LB
39pub mod generic;
40
487cf647
FG
41pub(crate) type BuiltinDeriveFn =
42 fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
43
44pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
dc9dc135
XL
45
46impl MultiItemModifier for BuiltinDerive {
dfeec247
XL
47 fn expand(
48 &self,
49 ecx: &mut ExtCtxt<'_>,
50 span: Span,
51 meta_item: &MetaItem,
52 item: Annotatable,
487cf647 53 is_derive_const: bool,
ba9703b0 54 ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
e1599b0c
XL
55 // FIXME: Built-in derives often forget to give spans contexts,
56 // so we are doing it here in a centralized way.
57 let span = ecx.with_def_site_ctxt(span);
dc9dc135 58 let mut items = Vec::new();
fc512014
XL
59 match item {
60 Annotatable::Stmt(stmt) => {
61 if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
487cf647
FG
62 (self.0)(
63 ecx,
64 span,
65 meta_item,
66 &Annotatable::Item(item),
67 &mut |a| {
68 // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
69 // to the function
70 items.push(Annotatable::Stmt(P(ast::Stmt {
71 id: ast::DUMMY_NODE_ID,
72 kind: ast::StmtKind::Item(a.expect_item()),
73 span,
74 })));
75 },
76 is_derive_const,
77 );
fc512014
XL
78 } else {
79 unreachable!("should have already errored on non-item statement")
80 }
81 }
82 _ => {
487cf647 83 (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const);
fc512014
XL
84 }
85 }
ba9703b0 86 ExpandResult::Ready(items)
dc9dc135
XL
87 }
88}
89
54a0048b 90/// Constructs an expression that calls an intrinsic
dfeec247
XL
91fn call_intrinsic(
92 cx: &ExtCtxt<'_>,
93 span: Span,
3dfed10e 94 intrinsic: Symbol,
dfeec247
XL
95 args: Vec<P<ast::Expr>>,
96) -> P<ast::Expr> {
e1599b0c 97 let span = cx.with_def_site_ctxt(span);
3dfed10e 98 let path = cx.std_path(&[sym::intrinsics, intrinsic]);
29967ef6
XL
99 cx.expr_call_global(span, path, args)
100}
101
102/// Constructs an expression that calls the `unreachable` intrinsic.
103fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
104 let span = cx.with_def_site_ctxt(span);
105 let path = cx.std_path(&[sym::intrinsics, sym::unreachable]);
106 let call = cx.expr_call_global(span, path, vec![]);
54a0048b
SL
107
108 cx.expr_block(P(ast::Block {
3157f602 109 stmts: vec![cx.stmt_expr(call)],
54a0048b
SL
110 id: ast::DUMMY_NODE_ID,
111 rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
3b2f2976 112 span,
1b1a35ee 113 tokens: None,
94222f64 114 could_be_bare_literal: false,
5bcae85e 115 }))
54a0048b 116}
e74abb32 117
e74abb32
XL
118// Injects `impl<...> Structural for ItemType<...> { }`. In particular,
119// does *not* add `where T: Structural` for parameters `T` in `...`.
120// (That's the main reason we cannot use TraitDef here.)
dfeec247
XL
121fn inject_impl_of_structural_trait(
122 cx: &mut ExtCtxt<'_>,
123 span: Span,
124 item: &Annotatable,
3dfed10e 125 structural_path: generic::ty::Path,
dfeec247
XL
126 push: &mut dyn FnMut(Annotatable),
127) {
487cf647 128 let Annotatable::Item(item) = item else {
5e7ed085 129 unreachable!();
e74abb32
XL
130 };
131
487cf647
FG
132 let generics = match &item.kind {
133 ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics,
e74abb32
XL
134 // Do not inject `impl Structural for Union`. (`PartialEq` does not
135 // support unions, so we will see error downstream.)
136 ItemKind::Union(..) => return,
137 _ => unreachable!(),
138 };
139
140 // Create generics param list for where clauses and impl headers
141 let mut generics = generics.clone();
142
2b03887a
FG
143 let ctxt = span.ctxt();
144
e74abb32
XL
145 // Create the type of `self`.
146 //
5099ac24 147 // in addition, remove defaults from generic params (impls cannot have them).
dfeec247
XL
148 let self_params: Vec<_> = generics
149 .params
150 .iter_mut()
151 .map(|param| match &mut param.kind {
2b03887a
FG
152 ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
153 cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
154 ),
dfeec247
XL
155 ast::GenericParamKind::Type { default } => {
156 *default = None;
2b03887a 157 ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
dfeec247 158 }
5869c6ff
XL
159 ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
160 *default = None;
2b03887a
FG
161 ast::GenericArg::Const(
162 cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
163 )
dfeec247
XL
164 }
165 })
166 .collect();
e74abb32
XL
167
168 let type_ident = item.ident;
169
170 let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
171 let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));
172
173 // It would be nice to also encode constraint `where Self: Eq` (by adding it
174 // onto `generics` cloned above). Unfortunately, that strategy runs afoul of
175 // rust-lang/rust#48214. So we perform that additional check in the compiler
176 // itself, instead of encoding it here.
177
178 // Keep the lint and stability attributes of the original item, to control
179 // how the generated implementation is linted.
f2b60f7d 180 let mut attrs = ast::AttrVec::new();
dfeec247
XL
181 attrs.extend(
182 item.attrs
183 .iter()
184 .filter(|a| {
185 [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
186 .contains(&a.name_or_empty())
187 })
188 .cloned(),
189 );
2b03887a 190 // Mark as `automatically_derived` to avoid some silly lints.
487cf647 191 attrs.push(cx.attr_word(sym::automatically_derived, span));
dfeec247
XL
192
193 let newitem = cx.item(
194 span,
3c0e092e 195 Ident::empty(),
dfeec247 196 attrs,
3c0e092e 197 ItemKind::Impl(Box::new(Impl {
74b04a01 198 unsafety: ast::Unsafe::No,
dfeec247
XL
199 polarity: ast::ImplPolarity::Positive,
200 defaultness: ast::Defaultness::Final,
74b04a01 201 constness: ast::Const::No,
dfeec247
XL
202 generics,
203 of_trait: Some(trait_ref),
204 self_ty: self_type,
205 items: Vec::new(),
94222f64 206 })),
dfeec247 207 );
e74abb32
XL
208
209 push(Annotatable::Item(newitem));
210}
064997fb
FG
211
212fn assert_ty_bounds(
213 cx: &mut ExtCtxt<'_>,
214 stmts: &mut Vec<ast::Stmt>,
215 ty: P<ast::Ty>,
216 span: Span,
217 assert_path: &[Symbol],
218) {
219 // Generate statement `let _: assert_path<ty>;`.
220 let span = cx.with_def_site_ctxt(span);
221 let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
222 stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
223}