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    &[ $( sym::$rest ),+ ]
11}}
12
13macro path_std($cx: expr, $span: expr, $($x:tt)*) {
14    generic::ty::new_path($cx, $span, pathvec!( $($x)* ), &[] )
15}
16
17pub(crate) mod clone;
18pub(crate) mod coerce_pointee;
19pub(crate) mod const_param_ty;
20pub(crate) mod copy;
21pub(crate) mod debug;
22pub(crate) mod default;
23pub(crate) mod eq;
24pub(crate) mod from;
25pub(crate) mod hash;
26pub(crate) mod ord;
27pub(crate) mod partial_eq;
28pub(crate) mod partial_ord;
29pub(crate) mod reborrow;
30
31pub(crate) mod generic;
32
33pub(crate) type BuiltinDeriveFn =
34    fn(&ExtCtxt<'_>, Span, &ast::Item, &mut dyn FnMut(Box<ast::Item>), bool);
35
36pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
37
38impl MultiItemModifier for BuiltinDerive {
39    fn expand(
40        &self,
41        ecx: &mut ExtCtxt<'_>,
42        span: Span,
43        _: &MetaItem,
44        item: Annotatable,
45        is_derive_const: bool,
46    ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
47        // FIXME: Built-in derives often forget to give spans contexts,
48        // so we are doing it here in a centralized way.
49        let span = ecx.with_def_site_ctxt(span);
50        let mut items = Vec::new();
51        match item {
52            Annotatable::Stmt(stmt) => {
53                if let ast::StmtKind::Item(item) = stmt.kind {
54                    (self.0)(
55                        ecx,
56                        span,
57                        &item,
58                        &mut |a| items.push(Annotatable::Stmt(Box::new(ecx.stmt_item(span, a)))),
59                        is_derive_const,
60                    );
61                } else {
62                    {
    ::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")
63                }
64            }
65            Annotatable::Item(item) => (self.0)(
66                ecx,
67                span,
68                &item,
69                &mut |a| items.push(Annotatable::Item(a)),
70                is_derive_const,
71            ),
72            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
73        }
74        ExpandResult::Ready(items)
75    }
76}
77
78/// Constructs an expression that calls an intrinsic
79fn call_intrinsic(
80    cx: &ExtCtxt<'_>,
81    span: Span,
82    intrinsic: Symbol,
83    args: ThinVec<Box<ast::Expr>>,
84) -> Box<ast::Expr> {
85    let span = cx.with_def_site_ctxt(span);
86    let path = cx.std_path(&[sym::intrinsics, intrinsic]);
87    cx.expr_call_global(span, path, args)
88}
89
90/// Constructs an expression that calls the `unreachable` intrinsic.
91fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> Box<ast::Expr> {
92    let call = call_intrinsic(cx, span, sym::unreachable, ThinVec::new());
93    cx.expr_block(Box::new(ast::Block {
94        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)],
95        id: ast::DUMMY_NODE_ID,
96        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
97        span,
98    }))
99}
100
101fn assert_ty_bounds(
102    cx: &ExtCtxt<'_>,
103    stmts: &mut ThinVec<ast::Stmt>,
104    ty: Box<ast::Ty>,
105    span: Span,
106    assert_path: &[Symbol],
107) {
108    // Generate statement `let _: assert_path<ty>;`.
109    let span = cx.with_def_site_ctxt(span);
110    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)]);
111    stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
112}