@@ -2,8 +2,9 @@ use crate::deriving::generic::ty::*;
2
2
use crate :: deriving:: generic:: * ;
3
3
use crate :: deriving:: path_std;
4
4
5
+ use rustc_ast as ast;
5
6
use rustc_ast:: ptr:: P ;
6
- use rustc_ast:: { self as ast , Expr , GenericArg , Generics , ItemKind , MetaItem , VariantData } ;
7
+ use rustc_ast:: { Expr , GenericArg , Generics , ItemKind , MetaItem , VariantData } ;
7
8
use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
8
9
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
9
10
use rustc_span:: Span ;
@@ -30,7 +31,8 @@ pub fn expand_deriving_clone(
30
31
// for deriving, Clone alone is not enough.
31
32
// Wherever Clone is implemented for fields is irrelevant so we don't assert it.
32
33
let bounds;
33
- let substructure;
34
+ let substructure_clone;
35
+ let substructure_clone_from;
34
36
let is_shallow;
35
37
match * item {
36
38
Annotatable :: Item ( ref annitem) => match annitem. kind {
@@ -45,36 +47,80 @@ pub fn expand_deriving_clone(
45
47
{
46
48
bounds = vec ! [ ] ;
47
49
is_shallow = true ;
48
- substructure = combine_substructure ( Box :: new ( |c, s, sub| {
50
+ substructure_clone = combine_substructure ( Box :: new ( |c, s, sub| {
49
51
cs_clone_shallow ( "Clone" , c, s, sub, false )
50
52
} ) ) ;
53
+ // There is no point in implementing `Clone::clone_from` for `Copy` types
54
+ // because they don't own resources to preserve.
55
+ // Default implementation would suffice and this would save compilation time a little.
56
+ substructure_clone_from = None ;
51
57
} else {
52
58
bounds = vec ! [ ] ;
53
59
is_shallow = false ;
54
- substructure =
60
+ substructure_clone =
55
61
combine_substructure ( Box :: new ( |c, s, sub| cs_clone ( "Clone" , c, s, sub) ) ) ;
62
+ if is_type_without_fields ( item) {
63
+ // It clones field by field
64
+ // so there is no point to generate it if there aren't any.
65
+ substructure_clone_from = None ;
66
+ } else {
67
+ substructure_clone_from =
68
+ Some ( combine_substructure ( Box :: new ( |c, s, sub| {
69
+ cs_clone_from ( "Clone" , c, s, sub)
70
+ } ) ) )
71
+ }
56
72
}
57
73
}
58
74
ItemKind :: Union ( ..) => {
59
75
bounds = vec ! [ Literal ( path_std!( marker:: Copy ) ) ] ;
60
76
is_shallow = true ;
61
- substructure = combine_substructure ( Box :: new ( |c, s, sub| {
77
+ substructure_clone = combine_substructure ( Box :: new ( |c, s, sub| {
62
78
cs_clone_shallow ( "Clone" , c, s, sub, true )
63
79
} ) ) ;
80
+ // Same reasoning as with `is_shallow`.
81
+ substructure_clone_from = None ;
64
82
}
65
83
_ => {
66
84
bounds = vec ! [ ] ;
67
85
is_shallow = false ;
68
- substructure =
86
+ substructure_clone =
69
87
combine_substructure ( Box :: new ( |c, s, sub| cs_clone ( "Clone" , c, s, sub) ) ) ;
88
+ substructure_clone_from = None ;
70
89
}
71
90
} ,
72
91
73
92
_ => cx. span_bug ( span, "`#[derive(Clone)]` on trait item or impl item" ) ,
74
93
}
75
94
76
95
let inline = cx. meta_word ( span, sym:: inline) ;
77
- let attrs = vec ! [ cx. attribute( inline) ] ;
96
+ let attrs = [ cx. attribute ( inline) ] ;
97
+
98
+ let mut methods = Vec :: with_capacity ( 2 ) ;
99
+ methods. push ( MethodDef {
100
+ name : sym:: clone,
101
+ generics : Bounds :: empty ( ) ,
102
+ explicit_self : borrowed_explicit_self ( ) ,
103
+ args : Vec :: new ( ) ,
104
+ ret_ty : Self_ ,
105
+ attributes : attrs. to_vec ( ) ,
106
+ is_unsafe : false ,
107
+ unify_fieldless_variants : false ,
108
+ combine_substructure : substructure_clone,
109
+ } ) ;
110
+ if let Some ( substructure_clone_from) = substructure_clone_from {
111
+ methods. push ( MethodDef {
112
+ name : sym:: clone_from,
113
+ generics : Bounds :: empty ( ) ,
114
+ explicit_self : mutable_explicit_self ( ) ,
115
+ args : vec ! [ ( borrowed_self( ) , sym:: other) ] ,
116
+ ret_ty : nil_ty ( ) ,
117
+ attributes : attrs. to_vec ( ) ,
118
+ is_unsafe : false ,
119
+ unify_fieldless_variants : false ,
120
+ combine_substructure : substructure_clone_from,
121
+ } )
122
+ }
123
+
78
124
let trait_def = TraitDef {
79
125
span,
80
126
attributes : Vec :: new ( ) ,
@@ -83,17 +129,7 @@ pub fn expand_deriving_clone(
83
129
generics : Bounds :: empty ( ) ,
84
130
is_unsafe : false ,
85
131
supports_unions : true ,
86
- methods : vec ! [ MethodDef {
87
- name: sym:: clone,
88
- generics: Bounds :: empty( ) ,
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
- } ] ,
132
+ methods,
97
133
associated_types : Vec :: new ( ) ,
98
134
} ;
99
135
@@ -157,6 +193,10 @@ fn cs_clone_shallow(
157
193
cx. expr_block ( cx. block ( trait_span, stmts) )
158
194
}
159
195
196
+ fn clone_fn_full_path ( cx : & ExtCtxt < ' _ > ) -> Vec < Ident > {
197
+ cx. std_path ( & [ sym:: clone, sym:: Clone , sym:: clone] )
198
+ }
199
+
160
200
fn cs_clone (
161
201
name : & str ,
162
202
cx : & mut ExtCtxt < ' _ > ,
@@ -165,7 +205,7 @@ fn cs_clone(
165
205
) -> P < Expr > {
166
206
let ctor_path;
167
207
let all_fields;
168
- let fn_path = cx . std_path ( & [ sym :: clone , sym :: Clone , sym :: clone ] ) ;
208
+ let fn_path = clone_fn_full_path ( cx ) ;
169
209
let subcall = |cx : & mut ExtCtxt < ' _ > , field : & FieldInfo < ' _ > | {
170
210
let args = vec ! [ cx. expr_addr_of( field. span, field. self_. clone( ) ) ] ;
171
211
cx. expr_call_global ( field. span , fn_path. clone ( ) , args)
@@ -217,3 +257,55 @@ fn cs_clone(
217
257
VariantData :: Unit ( ..) => cx. expr_path ( ctor_path) ,
218
258
}
219
259
}
260
+
261
+ fn cs_clone_from (
262
+ name : & str ,
263
+ cx : & mut ExtCtxt < ' _ > ,
264
+ trait_span : Span ,
265
+ substr : & Substructure < ' _ > ,
266
+ ) -> P < Expr > {
267
+ let all_fields = match * substr. fields {
268
+ Struct ( .., ref af) => af,
269
+ EnumMatching ( .., ref af) => af,
270
+ EnumNonMatchingCollapsed ( ref idents, ..) => {
271
+ // Cannot do something smart here.
272
+ // so emit `*self = other.clone();`
273
+
274
+ let [ self_, other] = idents[ ..] else {
275
+ cx. span_bug ( trait_span, & format ! ( "not exactly 2 arguments in `clone_from` in `derive({})`" , name) )
276
+ } ;
277
+ let self_ = cx. expr_deref ( trait_span, cx. expr_ident ( trait_span, self_) ) ;
278
+ let other = cx. expr_ident ( trait_span, other) ;
279
+ let clone_call = cx. expr_call_global (
280
+ trait_span,
281
+ clone_fn_full_path ( cx) ,
282
+ vec ! [ cx. expr_addr_of( trait_span, other) ] ,
283
+ ) ;
284
+ return cx. expr ( trait_span, ast:: ExprKind :: Assign ( self_, clone_call, trait_span) ) ;
285
+ }
286
+ StaticEnum ( ..) | StaticStruct ( ..) => {
287
+ cx. span_bug ( trait_span, & format ! ( "associated function in `derive({})`" , name) )
288
+ }
289
+ } ;
290
+
291
+ // Here we know that we have same fields in `&mut self` and in `other`
292
+ // so we can call `clone_from` of each of them.
293
+ let clone_from_path = cx. std_path ( & [ sym:: clone, sym:: Clone , sym:: clone_from] ) ;
294
+ let fields_clones_from: Vec < _ > = all_fields
295
+ . iter ( )
296
+ . map ( |field| {
297
+ if field. other . len ( ) != 1 {
298
+ cx. span_bug (
299
+ trait_span,
300
+ & format ! ( "not exactly 2 arguments in `clone_from` in `derive({})`" , name) ,
301
+ ) ;
302
+ }
303
+ cx. stmt_semi ( cx. expr_call_global (
304
+ field. span ,
305
+ clone_from_path. clone ( ) ,
306
+ vec ! [ field. self_. clone( ) , field. other[ 0 ] . clone( ) ] ,
307
+ ) )
308
+ } )
309
+ . collect ( ) ;
310
+ cx. expr_block ( cx. block ( trait_span, fields_clones_from) )
311
+ }
0 commit comments