]> git.lizzy.rs Git - rust.git/blob - src/librustc_builtin_macros/deriving/mod.rs
Rollup merge of #67734 - XAMPPRocky:master, r=skade
[rust.git] / src / librustc_builtin_macros / deriving / mod.rs
1 //! The compiler code necessary to implement the `#[derive]` extensions.
2
3 use rustc_expand::base::{Annotatable, ExtCtxt, MultiItemModifier};
4 use rustc_span::symbol::{sym, Symbol};
5 use rustc_span::Span;
6 use syntax::ast::{self, ItemKind, MetaItem};
7 use syntax::ptr::P;
8
9 macro path_local($x:ident) {
10     generic::ty::Path::new_local(stringify!($x))
11 }
12
13 macro pathvec_std($cx:expr, $($rest:ident)::+) {{
14     vec![ $( stringify!($rest) ),+ ]
15 }}
16
17 macro path_std($($x:tt)*) {
18     generic::ty::Path::new( pathvec_std!( $($x)* ) )
19 }
20
21 pub mod bounds;
22 pub mod clone;
23 pub mod debug;
24 pub mod decodable;
25 pub mod default;
26 pub mod encodable;
27 pub mod hash;
28
29 #[path = "cmp/eq.rs"]
30 pub mod eq;
31 #[path = "cmp/ord.rs"]
32 pub mod ord;
33 #[path = "cmp/partial_eq.rs"]
34 pub mod partial_eq;
35 #[path = "cmp/partial_ord.rs"]
36 pub mod partial_ord;
37
38 pub mod generic;
39
40 crate struct BuiltinDerive(
41     crate fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)),
42 );
43
44 impl MultiItemModifier for BuiltinDerive {
45     fn expand(
46         &self,
47         ecx: &mut ExtCtxt<'_>,
48         span: Span,
49         meta_item: &MetaItem,
50         item: Annotatable,
51     ) -> Vec<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         items
58     }
59 }
60
61 /// Constructs an expression that calls an intrinsic
62 fn call_intrinsic(
63     cx: &ExtCtxt<'_>,
64     span: Span,
65     intrinsic: &str,
66     args: Vec<P<ast::Expr>>,
67 ) -> 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);
71
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),
76         span,
77     }))
78 }
79
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(
84     cx: &mut ExtCtxt<'_>,
85     span: Span,
86     item: &Annotatable,
87     structural_path: generic::ty::Path<'_>,
88     push: &mut dyn FnMut(Annotatable),
89 ) {
90     let item = match *item {
91         Annotatable::Item(ref item) => item,
92         _ => {
93             // Non-Item derive is an error, but it should have been
94             // set earlier; see
95             // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
96             // librustc_expand/base.rs:Annotatable::derive_allowed()
97             return;
98         }
99     };
100
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,
106         _ => unreachable!(),
107     };
108
109     // Create generics param list for where clauses and impl headers
110     let mut generics = generics.clone();
111
112     // Create the type of `self`.
113     //
114     // in addition, remove defaults from type params (impls cannot have them).
115     let self_params: Vec<_> = generics
116         .params
117         .iter_mut()
118         .map(|param| match &mut param.kind {
119             ast::GenericParamKind::Lifetime => {
120                 ast::GenericArg::Lifetime(cx.lifetime(span, param.ident))
121             }
122             ast::GenericParamKind::Type { default } => {
123                 *default = None;
124                 ast::GenericArg::Type(cx.ty_ident(span, param.ident))
125             }
126             ast::GenericParamKind::Const { ty: _ } => {
127                 ast::GenericArg::Const(cx.const_ident(span, param.ident))
128             }
129         })
130         .collect();
131
132     let type_ident = item.ident;
133
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));
136
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.
141
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();
145     attrs.extend(
146         item.attrs
147             .iter()
148             .filter(|a| {
149                 [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
150                     .contains(&a.name_or_empty())
151             })
152             .cloned(),
153     );
154
155     let newitem = cx.item(
156         span,
157         ast::Ident::invalid(),
158         attrs,
159         ItemKind::Impl {
160             unsafety: ast::Unsafety::Normal,
161             polarity: ast::ImplPolarity::Positive,
162             defaultness: ast::Defaultness::Final,
163             generics,
164             of_trait: Some(trait_ref),
165             self_ty: self_type,
166             items: Vec::new(),
167         },
168     );
169
170     push(Annotatable::Item(newitem));
171 }