rustc_builtin_macros/deriving/
mod.rs

1//! The compiler code necessary to implement the `#[derive]` extensions.
2
3use rustc_ast as ast;
4use rustc_ast::ptr::P;
5use rustc_ast::{GenericArg, MetaItem};
6use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
7use rustc_span::{Span, Symbol, sym};
8use thin_vec::{ThinVec, thin_vec};
9
10macro path_local($x:ident) {
11    generic::ty::Path::new_local(sym::$x)
12}
13
14macro pathvec_std($($rest:ident)::+) {{
15    vec![ $( sym::$rest ),+ ]
16}}
17
18macro path_std($($x:tt)*) {
19    generic::ty::Path::new( pathvec_std!( $($x)* ) )
20}
21
22pub(crate) mod bounds;
23pub(crate) mod clone;
24pub(crate) mod coerce_pointee;
25pub(crate) mod debug;
26pub(crate) mod default;
27pub(crate) mod hash;
28
29#[path = "cmp/eq.rs"]
30pub(crate) mod eq;
31#[path = "cmp/ord.rs"]
32pub(crate) mod ord;
33#[path = "cmp/partial_eq.rs"]
34pub(crate) mod partial_eq;
35#[path = "cmp/partial_ord.rs"]
36pub(crate) mod partial_ord;
37
38pub(crate) mod generic;
39
40pub(crate) type BuiltinDeriveFn =
41    fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
42
43pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
44
45impl MultiItemModifier for BuiltinDerive {
46    fn expand(
47        &self,
48        ecx: &mut ExtCtxt<'_>,
49        span: Span,
50        meta_item: &MetaItem,
51        item: Annotatable,
52        is_derive_const: bool,
53    ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
54        // FIXME: Built-in derives often forget to give spans contexts,
55        // so we are doing it here in a centralized way.
56        let span = ecx.with_def_site_ctxt(span);
57        let mut items = Vec::new();
58        match item {
59            Annotatable::Stmt(stmt) => {
60                if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
61                    (self.0)(
62                        ecx,
63                        span,
64                        meta_item,
65                        &Annotatable::Item(item),
66                        &mut |a| {
67                            // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
68                            // to the function
69                            items.push(Annotatable::Stmt(P(ast::Stmt {
70                                id: ast::DUMMY_NODE_ID,
71                                kind: ast::StmtKind::Item(a.expect_item()),
72                                span,
73                            })));
74                        },
75                        is_derive_const,
76                    );
77                } else {
78                    unreachable!("should have already errored on non-item statement")
79                }
80            }
81            _ => {
82                (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const);
83            }
84        }
85        ExpandResult::Ready(items)
86    }
87}
88
89/// Constructs an expression that calls an intrinsic
90fn call_intrinsic(
91    cx: &ExtCtxt<'_>,
92    span: Span,
93    intrinsic: Symbol,
94    args: ThinVec<P<ast::Expr>>,
95) -> P<ast::Expr> {
96    let span = cx.with_def_site_ctxt(span);
97    let path = cx.std_path(&[sym::intrinsics, intrinsic]);
98    cx.expr_call_global(span, path, args)
99}
100
101/// Constructs an expression that calls the `unreachable` intrinsic.
102fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
103    let span = cx.with_def_site_ctxt(span);
104    let path = cx.std_path(&[sym::intrinsics, sym::unreachable]);
105    let call = cx.expr_call_global(span, path, ThinVec::new());
106
107    cx.expr_block(P(ast::Block {
108        stmts: thin_vec![cx.stmt_expr(call)],
109        id: ast::DUMMY_NODE_ID,
110        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
111        span,
112        tokens: None,
113        could_be_bare_literal: false,
114    }))
115}
116
117fn assert_ty_bounds(
118    cx: &ExtCtxt<'_>,
119    stmts: &mut ThinVec<ast::Stmt>,
120    ty: P<ast::Ty>,
121    span: Span,
122    assert_path: &[Symbol],
123) {
124    // Generate statement `let _: assert_path<ty>;`.
125    let span = cx.with_def_site_ctxt(span);
126    let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
127    stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
128}