Skip to main content

rustc_builtin_macros/deriving/
mod.rs

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