@@ -15,27 +15,18 @@ pub fn expand_deriving_clone(
15
15
item : & Annotatable ,
16
16
push : & mut dyn FnMut ( Annotatable ) ,
17
17
) {
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.
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.
31
- // Wherever Clone is implemented for fields is irrelevant so we don't assert it.
32
18
let bounds;
33
19
let substructure;
20
+ let is_union;
34
21
let is_shallow;
35
22
match * item {
36
23
Annotatable :: Item ( ref annitem) => match annitem. kind {
37
24
ItemKind :: Struct ( _, Generics { ref params, .. } )
38
25
| ItemKind :: Enum ( _, Generics { ref params, .. } ) => {
26
+ // FIXME: although the use of specialization already removes the need for checking whether
27
+ // the type already derives `Copy`, `rustc_scalar_valid_range_*` types derive
28
+ // `Clone` AND `Copy` and cannot be constructed unless unsafe blocks surround the expression,
29
+ // thus this part is preserved.
39
30
let container_id = cx. current_expansion . id . expn_data ( ) . parent . expect_local ( ) ;
40
31
let has_derive_copy = cx. resolver . has_derive_copy ( container_id) ;
41
32
if has_derive_copy
@@ -46,27 +37,27 @@ pub fn expand_deriving_clone(
46
37
bounds = vec ! [ ] ;
47
38
is_shallow = true ;
48
39
substructure = combine_substructure ( Box :: new ( |c, s, sub| {
49
- cs_clone_shallow ( "Clone" , c, s, sub, false )
40
+ cs_clone_shallow ( c, s, sub, false )
50
41
} ) ) ;
51
42
} else {
52
43
bounds = vec ! [ ] ;
53
44
is_shallow = false ;
54
- substructure =
55
- combine_substructure ( Box :: new ( |c, s, sub| cs_clone ( "Clone" , c, s, sub) ) ) ;
45
+ substructure = combine_substructure ( Box :: new ( |c, s, sub| cs_clone ( c, s, sub) ) ) ;
56
46
}
47
+ is_union = false ;
57
48
}
58
49
ItemKind :: Union ( ..) => {
59
50
bounds = vec ! [ Literal ( path_std!( marker:: Copy ) ) ] ;
60
51
is_shallow = true ;
61
- substructure = combine_substructure ( Box :: new ( |c , s , sub| {
62
- cs_clone_shallow ( "Clone" , c, s, sub, true )
63
- } ) ) ;
52
+ substructure =
53
+ combine_substructure ( Box :: new ( |c , s , sub| cs_clone_shallow ( c, s, sub, true ) ) ) ;
54
+ is_union = true ;
64
55
}
65
56
_ => {
66
57
bounds = vec ! [ ] ;
67
58
is_shallow = false ;
68
- substructure =
69
- combine_substructure ( Box :: new ( |c, s, sub| cs_clone ( "Clone" , c, s, sub) ) ) ;
59
+ is_union = false ;
60
+ substructure = combine_substructure ( Box :: new ( |c, s, sub| cs_clone ( c, s, sub) ) ) ;
70
61
}
71
62
} ,
72
63
@@ -78,7 +69,8 @@ pub fn expand_deriving_clone(
78
69
let trait_def = TraitDef {
79
70
span,
80
71
attributes : Vec :: new ( ) ,
81
- path : path_std ! ( clone:: Clone ) ,
72
+ path : if is_union { path_std ! ( clone:: Clone ) } else { path_std ! ( clone:: DerivedClone ) } ,
73
+ bound_current_trait : false ,
82
74
additional_bounds : bounds,
83
75
generics : Bounds :: empty ( ) ,
84
76
is_unsafe : false ,
@@ -89,19 +81,55 @@ pub fn expand_deriving_clone(
89
81
explicit_self: borrowed_explicit_self( ) ,
90
82
args: Vec :: new( ) ,
91
83
ret_ty: Self_ ,
92
- attributes: attrs,
84
+ attributes: attrs. clone ( ) ,
93
85
is_unsafe: false ,
94
86
unify_fieldless_variants: false ,
95
87
combine_substructure: substructure,
96
88
} ] ,
97
89
associated_types : Vec :: new ( ) ,
98
90
} ;
99
91
100
- trait_def. expand_ext ( cx, mitem, item, push, is_shallow)
92
+ trait_def. expand_ext ( cx, mitem, item, push, is_shallow) ;
93
+
94
+ if !is_union {
95
+ TraitDef {
96
+ span,
97
+ attributes : Vec :: new ( ) ,
98
+ path : path_std ! ( clone:: Clone ) ,
99
+ bound_current_trait : true ,
100
+ additional_bounds : vec ! [ ] ,
101
+ generics : Bounds :: empty ( ) ,
102
+ is_unsafe : false ,
103
+ supports_unions : false ,
104
+ methods : vec ! [ MethodDef {
105
+ name: sym:: clone,
106
+ generics: Bounds :: empty( ) ,
107
+ explicit_self: borrowed_explicit_self( ) ,
108
+ args: Vec :: new( ) ,
109
+ ret_ty: Self_ ,
110
+ attributes: attrs,
111
+ is_unsafe: false ,
112
+ unify_fieldless_variants: false ,
113
+ combine_substructure: combine_substructure( Box :: new( |c, s, _| {
114
+ c. expr_call(
115
+ s,
116
+ c. expr_path( c. path( s, c. std_path( & [ sym:: clone, sym:: try_copy] ) ) ) ,
117
+ vec![
118
+ c. expr_self( s) ,
119
+ c. expr_path(
120
+ c. path( s, c. std_path( & [ sym:: clone, sym:: DerivedClone , sym:: clone] ) ) ,
121
+ ) ,
122
+ ] ,
123
+ )
124
+ } ) ) ,
125
+ } ] ,
126
+ associated_types : vec ! [ ] ,
127
+ }
128
+ . expand_ext ( cx, mitem, item, push, true )
129
+ }
101
130
}
102
131
103
132
fn cs_clone_shallow (
104
- name : & str ,
105
133
cx : & mut ExtCtxt < ' _ > ,
106
134
trait_span : Span ,
107
135
substr : & Substructure < ' _ > ,
@@ -149,20 +177,15 @@ fn cs_clone_shallow(
149
177
}
150
178
_ => cx. span_bug (
151
179
trait_span,
152
- & format ! ( "unexpected substructure in shallow `derive({} )`" , name ) ,
180
+ & format ! ( "unexpected substructure in shallow `derive(Clone )`" ) ,
153
181
) ,
154
182
}
155
183
}
156
184
stmts. push ( cx. stmt_expr ( cx. expr_deref ( trait_span, cx. expr_self ( trait_span) ) ) ) ;
157
185
cx. expr_block ( cx. block ( trait_span, stmts) )
158
186
}
159
187
160
- fn cs_clone (
161
- name : & str ,
162
- cx : & mut ExtCtxt < ' _ > ,
163
- trait_span : Span ,
164
- substr : & Substructure < ' _ > ,
165
- ) -> P < Expr > {
188
+ fn cs_clone ( cx : & mut ExtCtxt < ' _ > , trait_span : Span , substr : & Substructure < ' _ > ) -> P < Expr > {
166
189
let ctor_path;
167
190
let all_fields;
168
191
let fn_path = cx. std_path ( & [ sym:: clone, sym:: Clone , sym:: clone] ) ;
@@ -184,10 +207,10 @@ fn cs_clone(
184
207
vdata = & variant. data ;
185
208
}
186
209
EnumNonMatchingCollapsed ( ..) => {
187
- cx. span_bug ( trait_span, & format ! ( "non-matching enum variants in `derive({} )`" , name , ) )
210
+ cx. span_bug ( trait_span, "non-matching enum variants in `derive(Clone )`" )
188
211
}
189
212
StaticEnum ( ..) | StaticStruct ( ..) => {
190
- cx. span_bug ( trait_span, & format ! ( "associated function in `derive({} )`" , name ) )
213
+ cx. span_bug ( trait_span, "associated function in `derive(Clone )`" )
191
214
}
192
215
}
193
216
@@ -199,7 +222,7 @@ fn cs_clone(
199
222
let Some ( ident) = field. name else {
200
223
cx. span_bug (
201
224
trait_span,
202
- & format ! ( "unnamed field in normal struct in `derive({} )`" , name , ) ,
225
+ "unnamed field in normal struct in `derive(Clone )`" ,
203
226
) ;
204
227
} ;
205
228
let call = subcall ( cx, field) ;
0 commit comments