1 //! The compiler code necessary to implement the `#[derive]` extensions.
5 use rustc_ast::{ImplKind, ItemKind, MetaItem};
6 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
7 use rustc_span::symbol::{sym, Ident, Symbol};
10 macro path_local($x:ident) {
11 generic::ty::Path::new_local(sym::$x)
14 macro pathvec_std($($rest:ident)::+) {{
15 vec![ $( sym::$rest ),+ ]
18 macro path_std($($x:tt)*) {
19 generic::ty::Path::new( pathvec_std!( $($x)* ) )
32 #[path = "cmp/ord.rs"]
34 #[path = "cmp/partial_eq.rs"]
36 #[path = "cmp/partial_ord.rs"]
41 crate struct BuiltinDerive(
42 crate fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)),
45 impl MultiItemModifier for BuiltinDerive {
48 ecx: &mut ExtCtxt<'_>,
52 ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
53 // FIXME: Built-in derives often forget to give spans contexts,
54 // so we are doing it here in a centralized way.
55 let span = ecx.with_def_site_ctxt(span);
56 let mut items = Vec::new();
58 Annotatable::Stmt(stmt) => {
59 if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
60 (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| {
61 // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
63 items.push(Annotatable::Stmt(P(ast::Stmt {
64 id: ast::DUMMY_NODE_ID,
65 kind: ast::StmtKind::Item(a.expect_item()),
70 unreachable!("should have already errored on non-item statement")
74 (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
77 ExpandResult::Ready(items)
81 /// Constructs an expression that calls an intrinsic
86 args: Vec<P<ast::Expr>>,
88 let span = cx.with_def_site_ctxt(span);
89 let path = cx.std_path(&[sym::intrinsics, intrinsic]);
90 cx.expr_call_global(span, path, args)
93 /// Constructs an expression that calls the `unreachable` intrinsic.
94 fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
95 let span = cx.with_def_site_ctxt(span);
96 let path = cx.std_path(&[sym::intrinsics, sym::unreachable]);
97 let call = cx.expr_call_global(span, path, vec![]);
99 cx.expr_block(P(ast::Block {
100 stmts: vec![cx.stmt_expr(call)],
101 id: ast::DUMMY_NODE_ID,
102 rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
105 could_be_bare_literal: false,
109 // Injects `impl<...> Structural for ItemType<...> { }`. In particular,
110 // does *not* add `where T: Structural` for parameters `T` in `...`.
111 // (That's the main reason we cannot use TraitDef here.)
112 fn inject_impl_of_structural_trait(
113 cx: &mut ExtCtxt<'_>,
116 structural_path: generic::ty::Path,
117 push: &mut dyn FnMut(Annotatable),
119 let item = match *item {
120 Annotatable::Item(ref item) => item,
124 let generics = match item.kind {
125 ItemKind::Struct(_, ref generics) | ItemKind::Enum(_, ref generics) => generics,
126 // Do not inject `impl Structural for Union`. (`PartialEq` does not
127 // support unions, so we will see error downstream.)
128 ItemKind::Union(..) => return,
132 // Create generics param list for where clauses and impl headers
133 let mut generics = generics.clone();
135 // Create the type of `self`.
137 // in addition, remove defaults from type params (impls cannot have them).
138 let self_params: Vec<_> = generics
141 .map(|param| match &mut param.kind {
142 ast::GenericParamKind::Lifetime => {
143 ast::GenericArg::Lifetime(cx.lifetime(span, param.ident))
145 ast::GenericParamKind::Type { default } => {
147 ast::GenericArg::Type(cx.ty_ident(span, param.ident))
149 ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
151 ast::GenericArg::Const(cx.const_ident(span, param.ident))
156 let type_ident = item.ident;
158 let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
159 let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));
161 // It would be nice to also encode constraint `where Self: Eq` (by adding it
162 // onto `generics` cloned above). Unfortunately, that strategy runs afoul of
163 // rust-lang/rust#48214. So we perform that additional check in the compiler
164 // itself, instead of encoding it here.
166 // Keep the lint and stability attributes of the original item, to control
167 // how the generated implementation is linted.
168 let mut attrs = Vec::new();
173 [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
174 .contains(&a.name_or_empty())
179 let newitem = cx.item(
183 ItemKind::Impl(Box::new(ImplKind {
184 unsafety: ast::Unsafe::No,
185 polarity: ast::ImplPolarity::Positive,
186 defaultness: ast::Defaultness::Final,
187 constness: ast::Const::No,
189 of_trait: Some(trait_ref),
195 push(Annotatable::Item(newitem));