1 //! The compiler code necessary to implement the `#[derive]` extensions.
3 use rustc_ast
::ast
::{self, ItemKind, MetaItem}
;
5 use rustc_expand
::base
::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}
;
6 use rustc_span
::symbol
::{sym, Symbol}
;
9 macro path_local($x
:ident
) {
10 generic
::ty
::Path
::new_local(stringify
!($x
))
13 macro pathvec_std($cx
:expr
, $
($rest
:ident
)::+) {{
14 vec
![ $
( stringify
!($rest
) ),+ ]
17 macro path_std($
($x
:tt
)*) {
18 generic
::ty
::Path
::new( pathvec_std
!( $
($x
)* ) )
31 #[path = "cmp/ord.rs"]
33 #[path = "cmp/partial_eq.rs"]
35 #[path = "cmp/partial_ord.rs"]
40 crate struct BuiltinDerive(
41 crate fn(&mut ExtCtxt
<'_
>, Span
, &MetaItem
, &Annotatable
, &mut dyn FnMut(Annotatable
)),
44 impl MultiItemModifier
for BuiltinDerive
{
47 ecx
: &mut ExtCtxt
<'_
>,
51 ) -> ExpandResult
<Vec
<Annotatable
>, Annotatable
> {
52 // FIXME: Built-in derives often forget to give spans contexts,
53 // so we are doing it here in a centralized way.
54 let span
= ecx
.with_def_site_ctxt(span
);
55 let mut items
= Vec
::new();
56 (self.0)(ecx
, span
, meta_item
, &item
, &mut |a
| items
.push(a
));
57 ExpandResult
::Ready(items
)
61 /// Constructs an expression that calls an intrinsic
66 args
: Vec
<P
<ast
::Expr
>>,
68 let span
= cx
.with_def_site_ctxt(span
);
69 let path
= cx
.std_path(&[sym
::intrinsics
, Symbol
::intern(intrinsic
)]);
70 let call
= cx
.expr_call_global(span
, path
, args
);
72 cx
.expr_block(P(ast
::Block
{
73 stmts
: vec
![cx
.stmt_expr(call
)],
74 id
: ast
::DUMMY_NODE_ID
,
75 rules
: ast
::BlockCheckMode
::Unsafe(ast
::CompilerGenerated
),
80 // Injects `impl<...> Structural for ItemType<...> { }`. In particular,
81 // does *not* add `where T: Structural` for parameters `T` in `...`.
82 // (That's the main reason we cannot use TraitDef here.)
83 fn inject_impl_of_structural_trait(
87 structural_path
: generic
::ty
::Path
<'_
>,
88 push
: &mut dyn FnMut(Annotatable
),
90 let item
= match *item
{
91 Annotatable
::Item(ref item
) => item
,
93 // Non-Item derive is an error, but it should have been
95 // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
96 // librustc_expand/base.rs:Annotatable::derive_allowed()
101 let generics
= match item
.kind
{
102 ItemKind
::Struct(_
, ref generics
) | ItemKind
::Enum(_
, ref generics
) => generics
,
103 // Do not inject `impl Structural for Union`. (`PartialEq` does not
104 // support unions, so we will see error downstream.)
105 ItemKind
::Union(..) => return,
109 // Create generics param list for where clauses and impl headers
110 let mut generics
= generics
.clone();
112 // Create the type of `self`.
114 // in addition, remove defaults from type params (impls cannot have them).
115 let self_params
: Vec
<_
> = generics
118 .map(|param
| match &mut param
.kind
{
119 ast
::GenericParamKind
::Lifetime
=> {
120 ast
::GenericArg
::Lifetime(cx
.lifetime(span
, param
.ident
))
122 ast
::GenericParamKind
::Type { default }
=> {
124 ast
::GenericArg
::Type(cx
.ty_ident(span
, param
.ident
))
126 ast
::GenericParamKind
::Const { ty: _ }
=> {
127 ast
::GenericArg
::Const(cx
.const_ident(span
, param
.ident
))
132 let type_ident
= item
.ident
;
134 let trait_ref
= cx
.trait_ref(structural_path
.to_path(cx
, span
, type_ident
, &generics
));
135 let self_type
= cx
.ty_path(cx
.path_all(span
, false, vec
![type_ident
], self_params
));
137 // It would be nice to also encode constraint `where Self: Eq` (by adding it
138 // onto `generics` cloned above). Unfortunately, that strategy runs afoul of
139 // rust-lang/rust#48214. So we perform that additional check in the compiler
140 // itself, instead of encoding it here.
142 // Keep the lint and stability attributes of the original item, to control
143 // how the generated implementation is linted.
144 let mut attrs
= Vec
::new();
149 [sym
::allow
, sym
::warn
, sym
::deny
, sym
::forbid
, sym
::stable
, sym
::unstable
]
150 .contains(&a
.name_or_empty())
155 let newitem
= cx
.item(
157 ast
::Ident
::invalid(),
160 unsafety
: ast
::Unsafe
::No
,
161 polarity
: ast
::ImplPolarity
::Positive
,
162 defaultness
: ast
::Defaultness
::Final
,
163 constness
: ast
::Const
::No
,
165 of_trait
: Some(trait_ref
),
171 push(Annotatable
::Item(newitem
));