Skip to main content

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::{GenericArg, MetaItem};
5use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
6use rustc_span::{Span, Symbol, sym};
7use thin_vec::{ThinVec, thin_vec};
8
9macro pathvec($($rest:ident)::+) {{
10    vec![ $( sym::$rest ),+ ]
11}}
12
13macro path_std($($x:tt)*) {
14    generic::ty::Path::new( pathvec!( $($x)* ) )
15}
16
17pub(crate) mod bounds;
18pub(crate) mod clone;
19pub(crate) mod coerce_pointee;
20pub(crate) mod debug;
21pub(crate) mod default;
22pub(crate) mod from;
23pub(crate) mod hash;
24pub(crate) mod reborrow;
25
26#[path = "cmp/eq.rs"]
27pub(crate) mod eq;
28#[path = "cmp/ord.rs"]
29pub(crate) mod ord;
30#[path = "cmp/partial_eq.rs"]
31pub(crate) mod partial_eq;
32#[path = "cmp/partial_ord.rs"]
33pub(crate) mod partial_ord;
34
35pub(crate) mod generic;
36
37pub(crate) type BuiltinDeriveFn =
38    fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
39
40pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
41
42impl MultiItemModifier for BuiltinDerive {
43    fn expand(
44        &self,
45        ecx: &mut ExtCtxt<'_>,
46        span: Span,
47        meta_item: &MetaItem,
48        item: Annotatable,
49        is_derive_const: bool,
50    ) -> ExpandResult<Vec<Annotatable>, 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        match item {
56            Annotatable::Stmt(stmt) => {
57                if let ast::StmtKind::Item(item) = stmt.kind {
58                    (self.0)(
59                        ecx,
60                        span,
61                        meta_item,
62                        &Annotatable::Item(item),
63                        &mut |a| {
64                            // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
65                            // to the function
66                            items.push(Annotatable::Stmt(Box::new(ast::Stmt {
67                                id: ast::DUMMY_NODE_ID,
68                                kind: ast::StmtKind::Item(a.expect_item()),
69                                span,
70                            })));
71                        },
72                        is_derive_const,
73                    );
74                } else {
75                    {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("should have already errored on non-item statement")));
}unreachable!("should have already errored on non-item statement")
76                }
77            }
78            _ => {
79                (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const);
80            }
81        }
82        ExpandResult::Ready(items)
83    }
84}
85
86/// Constructs an expression that calls an intrinsic
87fn call_intrinsic(
88    cx: &ExtCtxt<'_>,
89    span: Span,
90    intrinsic: Symbol,
91    args: ThinVec<Box<ast::Expr>>,
92) -> Box<ast::Expr> {
93    let span = cx.with_def_site_ctxt(span);
94    let path = cx.std_path(&[sym::intrinsics, intrinsic]);
95    cx.expr_call_global(span, path, args)
96}
97
98/// Constructs an expression that calls the `unreachable` intrinsic.
99fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Expr> {
100    let call = call_intrinsic(cx, span, sym::unreachable, ThinVec::new());
101    cx.expr_block(Box::new(ast::Block {
102        stmts: {
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(cx.stmt_expr(call));
    vec
}thin_vec![cx.stmt_expr(call)],
103        id: ast::DUMMY_NODE_ID,
104        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
105        span,
106    }))
107}
108
109fn assert_ty_bounds(
110    cx: &ExtCtxt<'_>,
111    stmts: &mut ThinVec<ast::Stmt>,
112    ty: Box<ast::Ty>,
113    span: Span,
114    assert_path: &[Symbol],
115) {
116    // Generate statement `let _: assert_path<ty>;`.
117    let span = cx.with_def_site_ctxt(span);
118    let assert_path = cx.path_all(span, true, cx.std_path(assert_path), ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [GenericArg::Type(ty)]))vec![GenericArg::Type(ty)]);
119    stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
120}