1 //! The compiler code necessary to implement the `#[derive]` extensions.
5 use rustc_ast
::{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();
57 (self.0)(ecx
, span
, meta_item
, &item
, &mut |a
| items
.push(a
));
58 ExpandResult
::Ready(items
)
62 /// Constructs an expression that calls an intrinsic
67 args
: Vec
<P
<ast
::Expr
>>,
69 let span
= cx
.with_def_site_ctxt(span
);
70 let path
= cx
.std_path(&[sym
::intrinsics
, intrinsic
]);
71 let call
= cx
.expr_call_global(span
, path
, args
);
73 cx
.expr_block(P(ast
::Block
{
74 stmts
: vec
![cx
.stmt_expr(call
)],
75 id
: ast
::DUMMY_NODE_ID
,
76 rules
: ast
::BlockCheckMode
::Unsafe(ast
::CompilerGenerated
),
81 // Injects `impl<...> Structural for ItemType<...> { }`. In particular,
82 // does *not* add `where T: Structural` for parameters `T` in `...`.
83 // (That's the main reason we cannot use TraitDef here.)
84 fn inject_impl_of_structural_trait(
88 structural_path
: generic
::ty
::Path
,
89 push
: &mut dyn FnMut(Annotatable
),
91 let item
= match *item
{
92 Annotatable
::Item(ref item
) => item
,
94 // Non-Item derive is an error, but it should have been
96 // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
97 // librustc_expand/base.rs:Annotatable::derive_allowed()
102 let generics
= match item
.kind
{
103 ItemKind
::Struct(_
, ref generics
) | ItemKind
::Enum(_
, ref generics
) => generics
,
104 // Do not inject `impl Structural for Union`. (`PartialEq` does not
105 // support unions, so we will see error downstream.)
106 ItemKind
::Union(..) => return,
110 // Create generics param list for where clauses and impl headers
111 let mut generics
= generics
.clone();
113 // Create the type of `self`.
115 // in addition, remove defaults from type params (impls cannot have them).
116 let self_params
: Vec
<_
> = generics
119 .map(|param
| match &mut param
.kind
{
120 ast
::GenericParamKind
::Lifetime
=> {
121 ast
::GenericArg
::Lifetime(cx
.lifetime(span
, param
.ident
))
123 ast
::GenericParamKind
::Type { default }
=> {
125 ast
::GenericArg
::Type(cx
.ty_ident(span
, param
.ident
))
127 ast
::GenericParamKind
::Const { ty: _, kw_span: _ }
=> {
128 ast
::GenericArg
::Const(cx
.const_ident(span
, param
.ident
))
133 let type_ident
= item
.ident
;
135 let trait_ref
= cx
.trait_ref(structural_path
.to_path(cx
, span
, type_ident
, &generics
));
136 let self_type
= cx
.ty_path(cx
.path_all(span
, false, vec
![type_ident
], self_params
));
138 // It would be nice to also encode constraint `where Self: Eq` (by adding it
139 // onto `generics` cloned above). Unfortunately, that strategy runs afoul of
140 // rust-lang/rust#48214. So we perform that additional check in the compiler
141 // itself, instead of encoding it here.
143 // Keep the lint and stability attributes of the original item, to control
144 // how the generated implementation is linted.
145 let mut attrs
= Vec
::new();
150 [sym
::allow
, sym
::warn
, sym
::deny
, sym
::forbid
, sym
::stable
, sym
::unstable
]
151 .contains(&a
.name_or_empty())
156 let newitem
= cx
.item(
161 unsafety
: ast
::Unsafe
::No
,
162 polarity
: ast
::ImplPolarity
::Positive
,
163 defaultness
: ast
::Defaultness
::Final
,
164 constness
: ast
::Const
::No
,
166 of_trait
: Some(trait_ref
),
172 push(Annotatable
::Item(newitem
));