]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_builtin_macros/src/deriving/clone.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / deriving / clone.rs
CommitLineData
9fa01778 1use crate::deriving::generic::ty::*;
dfeec247
XL
2use crate::deriving::generic::*;
3use crate::deriving::path_std;
9cc50fc6 4
74b04a01 5use rustc_ast::ptr::P;
3dfed10e 6use rustc_ast::{self as ast, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData};
dfeec247 7use rustc_expand::base::{Annotatable, ExtCtxt};
f9f354fc 8use rustc_span::symbol::{kw, sym, Ident, Symbol};
dfeec247 9use rustc_span::Span;
223e47cc 10
dfeec247
XL
11pub fn expand_deriving_clone(
12 cx: &mut ExtCtxt<'_>,
13 span: Span,
14 mitem: &MetaItem,
15 item: &Annotatable,
16 push: &mut dyn FnMut(Annotatable),
17) {
a7813a04
XL
18 // check if we can use a short form
19 //
20 // the short form is `fn clone(&self) -> Self { *self }`
21 //
22 // we can use the short form if:
23 // - the item is Copy (unfortunately, all we can check is whether it's also deriving Copy)
24 // - there are no generic parameters (after specialization this limitation can be removed)
25 // if we used the short form with generics, we'd have to bound the generics with
26 // Clone + Copy, and then there'd be no Clone impl at all if the user fills in something
27 // that is Clone but not Copy. and until specialization we can't write both impls.
9e0c209e
SL
28 // - the item is a union with Copy fields
29 // Unions with generic parameters still can derive Clone because they require Copy
30 // for deriving, Clone alone is not enough.
5e7ed085 31 // Wherever Clone is implemented for fields is irrelevant so we don't assert it.
a7813a04 32 let bounds;
a7813a04 33 let substructure;
9e0c209e 34 let is_shallow;
a7813a04 35 match *item {
dfeec247
XL
36 Annotatable::Item(ref annitem) => match annitem.kind {
37 ItemKind::Struct(_, Generics { ref params, .. })
38 | ItemKind::Enum(_, Generics { ref params, .. }) => {
136023e0
XL
39 let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
40 let has_derive_copy = cx.resolver.has_derive_copy(container_id);
41 if has_derive_copy
5869c6ff
XL
42 && !params
43 .iter()
44 .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
dfeec247
XL
45 {
46 bounds = vec![];
9e0c209e 47 is_shallow = true;
a7813a04 48 substructure = combine_substructure(Box::new(|c, s, sub| {
dfeec247 49 cs_clone_shallow("Clone", c, s, sub, false)
a7813a04 50 }));
dfeec247 51 } else {
a7813a04 52 bounds = vec![];
9e0c209e 53 is_shallow = false;
dfeec247
XL
54 substructure =
55 combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
a7813a04
XL
56 }
57 }
dfeec247 58 ItemKind::Union(..) => {
3dfed10e 59 bounds = vec![Literal(path_std!(marker::Copy))];
dfeec247
XL
60 is_shallow = true;
61 substructure = combine_substructure(Box::new(|c, s, sub| {
62 cs_clone_shallow("Clone", c, s, sub, true)
63 }));
64 }
65 _ => {
66 bounds = vec![];
67 is_shallow = false;
68 substructure =
69 combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
70 }
71 },
a7813a04 72
416331ca 73 _ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
a7813a04
XL
74 }
75
dc9dc135 76 let inline = cx.meta_word(span, sym::inline);
416331ca 77 let attrs = vec![cx.attribute(inline)];
970d7e83 78 let trait_def = TraitDef {
3b2f2976 79 span,
1a4d82fc 80 attributes: Vec::new(),
3dfed10e 81 path: path_std!(clone::Clone),
a7813a04 82 additional_bounds: bounds,
3dfed10e 83 generics: Bounds::empty(),
e9174d1e 84 is_unsafe: false,
9e0c209e 85 supports_unions: true,
5bcae85e 86 methods: vec![MethodDef {
3dfed10e
XL
87 name: sym::clone,
88 generics: Bounds::empty(),
dfeec247
XL
89 explicit_self: borrowed_explicit_self(),
90 args: Vec::new(),
91 ret_ty: Self_,
92 attributes: attrs,
93 is_unsafe: false,
94 unify_fieldless_variants: false,
95 combine_substructure: substructure,
96 }],
85aaf69f 97 associated_types: Vec::new(),
223e47cc
LB
98 };
99
9e0c209e
SL
100 trait_def.expand_ext(cx, mitem, item, push, is_shallow)
101}
102
dfeec247
XL
103fn cs_clone_shallow(
104 name: &str,
105 cx: &mut ExtCtxt<'_>,
106 trait_span: Span,
107 substr: &Substructure<'_>,
108 is_union: bool,
109) -> P<Expr> {
110 fn assert_ty_bounds(
111 cx: &mut ExtCtxt<'_>,
112 stmts: &mut Vec<ast::Stmt>,
113 ty: P<ast::Ty>,
114 span: Span,
115 helper_name: &str,
116 ) {
9e0c209e
SL
117 // Generate statement `let _: helper_name<ty>;`,
118 // set the expn ID so we can use the unstable struct.
e1599b0c 119 let span = cx.with_def_site_ctxt(span);
dfeec247
XL
120 let assert_path = cx.path_all(
121 span,
122 true,
123 cx.std_path(&[sym::clone, Symbol::intern(helper_name)]),
124 vec![GenericArg::Type(ty)],
125 );
9e0c209e
SL
126 stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
127 }
9fa01778 128 fn process_variant(cx: &mut ExtCtxt<'_>, stmts: &mut Vec<ast::Stmt>, variant: &VariantData) {
9e0c209e
SL
129 for field in variant.fields() {
130 // let _: AssertParamIsClone<FieldTy>;
131 assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsClone");
132 }
133 }
134
135 let mut stmts = Vec::new();
136 if is_union {
137 // let _: AssertParamIsCopy<Self>;
f9f354fc 138 let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper)));
9e0c209e
SL
139 assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, "AssertParamIsCopy");
140 } else {
141 match *substr.fields {
142 StaticStruct(vdata, ..) => {
143 process_variant(cx, &mut stmts, vdata);
144 }
145 StaticEnum(enum_def, ..) => {
146 for variant in &enum_def.variants {
e1599b0c 147 process_variant(cx, &mut stmts, &variant.data);
9e0c209e
SL
148 }
149 }
dfeec247
XL
150 _ => cx.span_bug(
151 trait_span,
136023e0 152 &format!("unexpected substructure in shallow `derive({})`", name),
dfeec247 153 ),
9e0c209e
SL
154 }
155 }
156 stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
157 cx.expr_block(cx.block(trait_span, stmts))
223e47cc
LB
158}
159
dfeec247
XL
160fn cs_clone(
161 name: &str,
162 cx: &mut ExtCtxt<'_>,
163 trait_span: Span,
164 substr: &Substructure<'_>,
165) -> P<Expr> {
1a4d82fc 166 let ctor_path;
970d7e83 167 let all_fields;
dc9dc135 168 let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
9fa01778 169 let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo<'_>| {
1a4d82fc 170 let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
9e0c209e 171 cx.expr_call_global(field.span, fn_path.clone(), args)
1a4d82fc 172 };
970d7e83 173
7453a54e 174 let vdata;
970d7e83 175 match *substr.fields {
7453a54e 176 Struct(vdata_, ref af) => {
1a4d82fc 177 ctor_path = cx.path(trait_span, vec![substr.type_ident]);
970d7e83 178 all_fields = af;
7453a54e 179 vdata = vdata_;
223e47cc 180 }
041b39d2 181 EnumMatching(.., variant, ref af) => {
e1599b0c 182 ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.ident]);
970d7e83 183 all_fields = af;
e1599b0c 184 vdata = &variant.data;
5bcae85e 185 }
dfeec247
XL
186 EnumNonMatchingCollapsed(..) => {
187 cx.span_bug(trait_span, &format!("non-matching enum variants in `derive({})`", name,))
188 }
1a4d82fc 189 StaticEnum(..) | StaticStruct(..) => {
e74abb32 190 cx.span_bug(trait_span, &format!("associated function in `derive({})`", name))
1a4d82fc 191 }
223e47cc
LB
192 }
193
9e0c209e
SL
194 match *vdata {
195 VariantData::Struct(..) => {
dfeec247
XL
196 let fields = all_fields
197 .iter()
9e0c209e 198 .map(|field| {
5e7ed085
FG
199 let Some(ident) = field.name else {
200 cx.span_bug(
dfeec247
XL
201 trait_span,
202 &format!("unnamed field in normal struct in `derive({})`", name,),
5e7ed085 203 );
9e0c209e
SL
204 };
205 let call = subcall(cx, field);
206 cx.field_imm(field.span, ident, call)
207 })
208 .collect::<Vec<_>>();
a7813a04 209
9e0c209e
SL
210 cx.expr_struct(trait_span, ctor_path, fields)
211 }
212 VariantData::Tuple(..) => {
213 let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect();
214 let path = cx.expr_path(ctor_path);
215 cx.expr_call(trait_span, path, subcalls)
7453a54e 216 }
9e0c209e 217 VariantData::Unit(..) => cx.expr_path(ctor_path),
970d7e83 218 }
223e47cc 219}