@@ -21,6 +21,38 @@ use syntax::ast_map::path;
21
21
use syntax:: ast_util;
22
22
use syntax:: ast_util:: local_def;
23
23
24
+ /// The kind of deriving method this is.
25
+ enum DerivingKind {
26
+ BoolKind , // fn f(&self, other: &other) -> bool
27
+ UnitKind , // fn f(&self) -> ()
28
+ }
29
+
30
+ impl DerivingKind {
31
+ static fn of_item( ccx: @crate_ctxt , method_did : ast:: def_id )
32
+ -> DerivingKind {
33
+ let item_type = ty:: lookup_item_type ( ccx. tcx , method_did) . ty ;
34
+ match ty:: get( item_type) . sty {
35
+ ty:: ty_fn( ref f) => {
36
+ match ty:: get( f. sig. output) . sty {
37
+ ty:: ty_bool => BoolKind ,
38
+ ty:: ty_nil => UnitKind ,
39
+ _ => {
40
+ // FIXME (#3957): Report this earlier.
41
+ ccx. tcx. sess. fatal( ~"attempt to automatically derive \
42
+ derive an implementation of a \
43
+ function returning something \
44
+ other than bool or ( ) ") ;
45
+ }
46
+ }
47
+ }
48
+ _ => {
49
+ ccx. tcx. sess. bug( ~"DerivingKind :: of_item( ) : method def ID \
50
+ didn' t have a function type ") ;
51
+ }
52
+ }
53
+ }
54
+ }
55
+
24
56
/// The main "translation" pass for automatically-derived impls. Generates
25
57
/// code for monomorphic methods only. Other methods will be generated when
26
58
/// they are invoked with specific type parameters; see
@@ -36,15 +68,16 @@ pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
36
68
impl_def_id) ;
37
69
38
70
for method_dids. each |method_did| {
71
+ let kind = DerivingKind :: of_item ( ccx, * method_did) ;
39
72
let llfn = get_item_val ( ccx, method_did. node ) ;
40
73
match ty:: get ( self_ty. ty ) . sty {
41
74
ty:: ty_class( * ) => {
42
75
trans_deriving_struct_method ( ccx, llfn, impl_def_id,
43
- self_ty. ty ) ;
76
+ self_ty. ty , kind ) ;
44
77
}
45
78
ty:: ty_enum( * ) => {
46
79
trans_deriving_enum_method ( ccx, llfn, impl_def_id,
47
- self_ty. ty ) ;
80
+ self_ty. ty , kind ) ;
48
81
}
49
82
_ => {
50
83
ccx. tcx . sess . bug ( ~"translation of non-struct deriving \
@@ -54,8 +87,11 @@ pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
54
87
}
55
88
}
56
89
57
- fn trans_deriving_struct_method ( ccx : @crate_ctxt , llfn : ValueRef ,
58
- impl_did : def_id , self_ty : ty:: t ) {
90
+ fn trans_deriving_struct_method ( ccx : @crate_ctxt ,
91
+ llfn : ValueRef ,
92
+ impl_did : def_id ,
93
+ self_ty : ty:: t ,
94
+ kind : DerivingKind ) {
59
95
let _icx = ccx. insn_ctxt ( "trans_deriving_struct_method" ) ;
60
96
let fcx = new_fn_ctxt ( ccx, ~[ ] , llfn, None ) ;
61
97
let top_bcx = top_scope_block ( fcx, None ) ;
@@ -64,7 +100,14 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
64
100
65
101
let llselfty = type_of ( ccx, self_ty) ;
66
102
let llselfval = PointerCast ( bcx, fcx. llenv , T_ptr ( llselfty) ) ;
67
- let llotherval = llvm:: LLVMGetParam ( llfn, 2 ) ;
103
+
104
+ // If there is an "other" value, then get it. The "other" value is the
105
+ // value we're comparing against in the case of Eq and Ord.
106
+ let llotherval_opt;
107
+ match kind {
108
+ BoolKind => llotherval_opt = Some ( llvm:: LLVMGetParam ( llfn, 2 ) ) ,
109
+ UnitKind => llotherval_opt = None
110
+ }
68
111
69
112
let struct_field_tys;
70
113
match ty:: get ( self_ty) . sty {
@@ -82,27 +125,45 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
82
125
for ccx. tcx. deriving_struct_methods. get( impl_did) . eachi
83
126
|i, derived_method_info| {
84
127
let llselfval = GEPi ( bcx, llselfval, [ 0 , 0 , i] ) ;
85
- let llotherval = GEPi ( bcx, llotherval, [ 0 , 0 , i] ) ;
128
+
129
+ let llotherval_opt = llotherval_opt. map (
130
+ |llotherval| GEPi ( bcx, * llotherval, [ 0 , 0 , i] ) ) ;
86
131
87
132
let self_ty = struct_field_tys[ i] . mt . ty ;
88
133
bcx = call_substructure_method ( bcx, derived_method_info, self_ty,
89
- llselfval, llotherval) ;
134
+ llselfval, llotherval_opt) ;
135
+
136
+ // If this derived method is of boolean kind, return immediately if
137
+ // the call to the substructure method returned false.
138
+ match kind {
139
+ BoolKind => {
140
+ let next_block = sub_block ( top_bcx, ~"next") ;
141
+ let llcond = Load ( bcx, fcx. llretptr ) ;
142
+ CondBr ( bcx, llcond, next_block. llbb , fcx. llreturn ) ;
143
+ bcx = next_block;
144
+ }
145
+ UnitKind => { } // Unconditionally continue.
146
+ }
147
+ }
90
148
91
- // Return immediately if the call returned false.
92
- let next_block = sub_block ( top_bcx, ~"next") ;
93
- let llcond = Load ( bcx, fcx. llretptr ) ;
94
- CondBr ( bcx, llcond, next_block. llbb , fcx. llreturn ) ;
95
- bcx = next_block;
149
+ // Store true if necessary.
150
+ match kind {
151
+ BoolKind => Store ( bcx, C_bool ( true ) , fcx. llretptr ) ,
152
+ UnitKind => { }
96
153
}
97
154
98
- Store ( bcx, C_bool ( true ) , fcx. llretptr ) ;
99
155
Br ( bcx, fcx. llreturn ) ;
100
156
101
157
finish_fn ( fcx, lltop) ;
102
158
}
103
159
104
- fn trans_deriving_enum_method ( ccx : @crate_ctxt , llfn : ValueRef ,
105
- impl_did : def_id , self_ty : ty:: t ) {
160
+ // This could have been combined with trans_deriving_struct_method, but it
161
+ // would probably be too big and hard to understand.
162
+ fn trans_deriving_enum_method ( ccx : @crate_ctxt ,
163
+ llfn : ValueRef ,
164
+ impl_did : def_id ,
165
+ self_ty : ty:: t ,
166
+ kind : DerivingKind ) {
106
167
let _icx = ccx. insn_ctxt ( "trans_deriving_enum_method" ) ;
107
168
let fcx = new_fn_ctxt ( ccx, ~[ ] , llfn, None ) ;
108
169
let top_bcx = top_scope_block ( fcx, None ) ;
@@ -111,7 +172,12 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
111
172
112
173
let llselfty = type_of ( ccx, self_ty) ;
113
174
let llselfval = PointerCast ( bcx, fcx. llenv , T_ptr ( llselfty) ) ;
114
- let llotherval = llvm:: LLVMGetParam ( llfn, 2 ) ;
175
+
176
+ let llotherval_opt;
177
+ match kind {
178
+ UnitKind => llotherval_opt = None ,
179
+ BoolKind => llotherval_opt = Some ( llvm:: LLVMGetParam ( llfn, 2 ) )
180
+ }
115
181
116
182
let enum_id, enum_substs, enum_variant_infos;
117
183
match ty:: get ( self_ty) . sty {
@@ -127,11 +193,18 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
127
193
}
128
194
}
129
195
130
- // Create the "no match" basic block. This is a basic block that does
131
- // nothing more than return false.
132
- let nomatch_bcx = sub_block ( top_bcx, ~"no_match") ;
133
- Store ( nomatch_bcx, C_bool ( false ) , fcx. llretptr ) ;
134
- Br ( nomatch_bcx, fcx. llreturn ) ;
196
+ // Create the "no match" basic block, if necessary. This is a basic block
197
+ // that does nothing more than return false.
198
+ let nomatch_bcx_opt;
199
+ match kind {
200
+ BoolKind => {
201
+ let nomatch_bcx = sub_block ( top_bcx, ~"no_match") ;
202
+ Store ( nomatch_bcx, C_bool ( false ) , fcx. llretptr ) ;
203
+ Br ( nomatch_bcx, fcx. llreturn ) ;
204
+ nomatch_bcx_opt = Some ( nomatch_bcx) ;
205
+ }
206
+ UnitKind => nomatch_bcx_opt = None
207
+ }
135
208
136
209
// Create the "unreachable" basic block.
137
210
let unreachable_bcx = sub_block ( top_bcx, ~"unreachable") ;
@@ -144,11 +217,13 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
144
217
if n_variants != 1 {
145
218
// Grab the two discriminants.
146
219
let llselfdiscrim = Load ( bcx, GEPi ( bcx, llselfval, [ 0 , 0 ] ) ) ;
147
- let llotherdiscrim = Load ( bcx, GEPi ( bcx, llotherval, [ 0 , 0 ] ) ) ;
220
+ let llotherdiscrim_opt = llotherval_opt. map (
221
+ |llotherval| Load ( bcx, GEPi ( bcx, * llotherval, [ 0 , 0 ] ) ) ) ;
148
222
149
223
// Skip over the discriminants and compute the address of the payload.
150
224
let llselfpayload = GEPi ( bcx, llselfval, [ 0 , 1 ] ) ;
151
- let llotherpayload = GEPi ( bcx, llotherval, [ 0 , 1 ] ) ;
225
+ let llotherpayload_opt = llotherval_opt. map (
226
+ |llotherval| GEPi ( bcx, * llotherval, [ 0 , 1 ] ) ) ;
152
227
153
228
// Create basic blocks for the outer switch.
154
229
let outer_bcxs = vec:: from_fn (
@@ -169,46 +244,71 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
169
244
enum_variant_infos[ self_variant_index] . id ;
170
245
let llselfval = GEP_enum ( match_bcx, llselfpayload, enum_id,
171
246
variant_def_id, enum_substs. tps , i) ;
172
- let llotherval = GEP_enum ( match_bcx, llotherpayload,
173
- enum_id, variant_def_id,
174
- enum_substs. tps , i) ;
247
+
248
+ let llotherval_opt = llotherpayload_opt. map ( |llotherpayload|
249
+ GEP_enum ( match_bcx, * llotherpayload, enum_id,
250
+ variant_def_id, enum_substs. tps , i) ) ;
175
251
176
252
let self_ty = enum_variant_infos[ self_variant_index] . args [ i] ;
177
253
match_bcx = call_substructure_method ( match_bcx,
178
254
derived_method_info,
179
255
self_ty,
180
256
llselfval,
181
- llotherval) ;
182
-
183
- // Return immediately if the call to the substructure returned
184
- // false.
185
- let next_bcx = sub_block (
186
- top_bcx, fmt ! ( "next_%u_%u" , self_variant_index, i) ) ;
187
- let llcond = Load ( match_bcx, fcx. llretptr ) ;
188
- CondBr ( match_bcx, llcond, next_bcx. llbb , fcx. llreturn ) ;
189
- match_bcx = next_bcx;
257
+ llotherval_opt) ;
258
+
259
+ // If this is a boolean-kind deriving method, then return
260
+ // immediately if the call to the substructure returned false.
261
+ match kind {
262
+ BoolKind => {
263
+ let next_bcx = sub_block ( top_bcx,
264
+ fmt ! ( "next_%u_%u" ,
265
+ self_variant_index,
266
+ i) ) ;
267
+ let llcond = Load ( match_bcx, fcx. llretptr ) ;
268
+ CondBr ( match_bcx,
269
+ llcond,
270
+ next_bcx. llbb ,
271
+ fcx. llreturn ) ;
272
+ match_bcx = next_bcx;
273
+ }
274
+ UnitKind => { }
275
+ }
276
+ }
277
+
278
+ // Store true in the return pointer if this is a boolean-kind
279
+ // deriving method.
280
+ match kind {
281
+ BoolKind => Store ( match_bcx, C_bool ( true ) , fcx. llretptr ) ,
282
+ UnitKind => { }
190
283
}
191
284
192
285
// Finish up the matching block.
193
- Store ( match_bcx, C_bool ( true ) , fcx. llretptr ) ;
194
286
Br ( match_bcx, fcx. llreturn ) ;
195
287
196
- // Build the inner switch.
197
- let llswitch = Switch (
198
- * bcx, llotherdiscrim, unreachable_bcx. llbb , n_variants) ;
199
- for uint:: range( 0 , n_variants) |other_variant_index| {
200
- let discriminant =
201
- enum_variant_infos[ other_variant_index] . disr_val ;
202
- if self_variant_index == other_variant_index {
203
- // This is the potentially-matching case.
204
- AddCase ( llswitch,
205
- C_int ( ccx, discriminant) ,
206
- top_match_bcx. llbb ) ;
207
- } else {
208
- // This is always a non-matching case.
209
- AddCase ( llswitch,
210
- C_int ( ccx, discriminant) ,
211
- nomatch_bcx. llbb ) ;
288
+ // If this is a boolean-kind derived method, build the inner
289
+ // switch. Otherwise, just jump to the matching case.
290
+ match llotherdiscrim_opt {
291
+ None => Br ( * bcx, top_match_bcx. llbb ) ,
292
+ Some ( copy llotherdiscrim) => {
293
+ let llswitch = Switch ( * bcx,
294
+ llotherdiscrim,
295
+ unreachable_bcx. llbb ,
296
+ n_variants) ;
297
+ for uint:: range( 0 , n_variants) |other_variant_index| {
298
+ let discriminant =
299
+ enum_variant_infos[ other_variant_index] . disr_val ;
300
+ if self_variant_index == other_variant_index {
301
+ // This is the potentially-matching case.
302
+ AddCase ( llswitch,
303
+ C_int ( ccx, discriminant) ,
304
+ top_match_bcx. llbb ) ;
305
+ } else {
306
+ // This is always a non-matching case.
307
+ AddCase ( llswitch,
308
+ C_int ( ccx, discriminant) ,
309
+ nomatch_bcx_opt. get ( ) . llbb ) ;
310
+ }
311
+ }
212
312
}
213
313
}
214
314
}
@@ -233,7 +333,7 @@ fn call_substructure_method(bcx: block,
233
333
derived_field_info : & DerivedFieldInfo ,
234
334
self_ty : ty:: t ,
235
335
llselfval : ValueRef ,
236
- llotherval : ValueRef ) -> block {
336
+ llotherval_opt : Option < ValueRef > ) -> block {
237
337
let fcx = bcx. fcx ;
238
338
let ccx = fcx. ccx ;
239
339
@@ -273,12 +373,18 @@ fn call_substructure_method(bcx: block,
273
373
}
274
374
} ;
275
375
376
+ let arg_values;
377
+ match llotherval_opt {
378
+ None => arg_values = ArgVals ( ~[ ] ) ,
379
+ Some ( copy llotherval) => arg_values = ArgVals ( ~[ llotherval] )
380
+ }
381
+
276
382
callee:: trans_call_inner ( bcx,
277
383
None ,
278
384
fn_expr_tpbt. ty ,
279
385
ty:: mk_bool ( ccx. tcx ) ,
280
386
cb,
281
- ArgVals ( ~ [ llotherval ] ) ,
387
+ move arg_values ,
282
388
SaveIn ( fcx. llretptr ) ,
283
389
DontAutorefArg )
284
390
}
0 commit comments