rustc_builtin_macros/deriving/
mod.rs1use 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 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
80fn 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
92fn 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
97fn 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 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}