@@ -15,27 +15,18 @@ pub fn expand_deriving_clone(
1515 item : & Annotatable ,
1616 push : & mut dyn FnMut ( Annotatable ) ,
1717) {
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.
3218 let bounds;
3319 let substructure;
20+ let is_union;
3421 let is_shallow;
3522 match * item {
3623 Annotatable :: Item ( ref annitem) => match annitem. kind {
3724 ItemKind :: Struct ( _, Generics { ref params, .. } )
3825 | 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.
3930 let container_id = cx. current_expansion . id . expn_data ( ) . parent . expect_local ( ) ;
4031 let has_derive_copy = cx. resolver . has_derive_copy ( container_id) ;
4132 if has_derive_copy
@@ -46,27 +37,27 @@ pub fn expand_deriving_clone(
4637 bounds = vec ! [ ] ;
4738 is_shallow = true ;
4839 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 )
5041 } ) ) ;
5142 } else {
5243 bounds = vec ! [ ] ;
5344 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) ) ) ;
5646 }
47+ is_union = false ;
5748 }
5849 ItemKind :: Union ( ..) => {
5950 bounds = vec ! [ Literal ( path_std!( marker:: Copy ) ) ] ;
6051 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 ;
6455 }
6556 _ => {
6657 bounds = vec ! [ ] ;
6758 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) ) ) ;
7061 }
7162 } ,
7263
@@ -78,7 +69,8 @@ pub fn expand_deriving_clone(
7869 let trait_def = TraitDef {
7970 span,
8071 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 ,
8274 additional_bounds : bounds,
8375 generics : Bounds :: empty ( ) ,
8476 is_unsafe : false ,
@@ -89,19 +81,55 @@ pub fn expand_deriving_clone(
8981 explicit_self: borrowed_explicit_self( ) ,
9082 args: Vec :: new( ) ,
9183 ret_ty: Self_ ,
92- attributes: attrs,
84+ attributes: attrs. clone ( ) ,
9385 is_unsafe: false ,
9486 unify_fieldless_variants: false ,
9587 combine_substructure: substructure,
9688 } ] ,
9789 associated_types : Vec :: new ( ) ,
9890 } ;
9991
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+ }
101130}
102131
103132fn cs_clone_shallow (
104- name : & str ,
105133 cx : & mut ExtCtxt < ' _ > ,
106134 trait_span : Span ,
107135 substr : & Substructure < ' _ > ,
@@ -149,20 +177,15 @@ fn cs_clone_shallow(
149177 }
150178 _ => cx. span_bug (
151179 trait_span,
152- & format ! ( "unexpected substructure in shallow `derive({} )`" , name ) ,
180+ & format ! ( "unexpected substructure in shallow `derive(Clone )`" ) ,
153181 ) ,
154182 }
155183 }
156184 stmts. push ( cx. stmt_expr ( cx. expr_deref ( trait_span, cx. expr_self ( trait_span) ) ) ) ;
157185 cx. expr_block ( cx. block ( trait_span, stmts) )
158186}
159187
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 > {
166189 let ctor_path;
167190 let all_fields;
168191 let fn_path = cx. std_path ( & [ sym:: clone, sym:: Clone , sym:: clone] ) ;
@@ -184,10 +207,10 @@ fn cs_clone(
184207 vdata = & variant. data ;
185208 }
186209 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 )`" )
188211 }
189212 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 )`" )
191214 }
192215 }
193216
@@ -199,7 +222,7 @@ fn cs_clone(
199222 let Some ( ident) = field. name else {
200223 cx. span_bug (
201224 trait_span,
202- & format ! ( "unnamed field in normal struct in `derive({} )`" , name , ) ,
225+ "unnamed field in normal struct in `derive(Clone )`" ,
203226 ) ;
204227 } ;
205228 let call = subcall ( cx, field) ;
0 commit comments