Mercurial > projects > ddmd
annotate dmd/TypeFunction.d @ 129:010eb8f0e18d
further work on dmd test suite
author | korDen |
---|---|
date | Sun, 05 Sep 2010 15:32:22 +0400 |
parents | 1765f3ef917d |
children | 60bb0fe4563e |
rev | line source |
---|---|
0 | 1 module dmd.TypeFunction; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.TypeNext; |
5 import dmd.TypeSArray; | |
6 import dmd.TypeArray; | |
123 | 7 import dmd.TemplateTupleParameter; |
0 | 8 import dmd.ArrayTypes; |
9 import dmd.LINK; | |
10 import dmd.StructDeclaration; | |
11 import dmd.TypeStruct; | |
12 import dmd.Global; | |
13 import dmd.STC; | |
14 import dmd.MOD; | |
73 | 15 import dmd.PROT; |
123 | 16 import dmd.TypeIdentifier; |
17 import dmd.TemplateParameter; | |
129 | 18 import dmd.TypeInfoFunctionDeclaration; |
123 | 19 import dmd.Tuple; |
0 | 20 import dmd.Type; |
21 import dmd.Loc; | |
22 import dmd.Scope; | |
23 import dmd.Identifier; | |
24 import dmd.OutBuffer; | |
25 import dmd.HdrGenState; | |
26 import dmd.CppMangleState; | |
27 import dmd.TypeInfoDeclaration; | |
28 import dmd.MATCH; | |
29 import dmd.Argument; | |
30 import dmd.Expression; | |
31 import dmd.RET; | |
32 import dmd.TY; | |
33 import dmd.Util; | |
123 | 34 import dmd.TemplateInstance : isTuple; |
0 | 35 |
36 import dmd.backend.TYPE; | |
37 import dmd.backend.PARAM; | |
38 import dmd.backend.Util; | |
39 import dmd.backend.TYM; | |
40 import dmd.backend.TF; | |
41 import dmd.backend.mTY; | |
42 | |
43 import core.stdc.stdlib; | |
44 import core.stdc.string; | |
45 | |
129 | 46 import std.stdio; |
47 | |
0 | 48 class TypeFunction : TypeNext |
49 { | |
50 // .next is the return type | |
51 | |
52 Arguments parameters; // function parameters | |
53 int varargs; // 1: T t, ...) style for variable number of arguments | |
54 // 2: T t ...) style for variable number of arguments | |
55 bool isnothrow; // true: nothrow | |
56 bool ispure; // true: pure | |
57 bool isproperty; // can be called without parentheses | |
58 bool isref; // true: returns a reference | |
59 LINK linkage; // calling convention | |
60 | |
61 int inuse; | |
62 | |
63 this(Arguments parameters, Type treturn, int varargs, LINK linkage) | |
64 { | |
65 super(TY.Tfunction, treturn); | |
66 | |
67 //if (!treturn) *(char*)0=0; | |
68 // assert(treturn); | |
69 assert(0 <= varargs && varargs <= 2); | |
70 this.parameters = parameters; | |
71 this.varargs = varargs; | |
72 this.linkage = linkage; | |
73 } | |
74 | |
72 | 75 override Type syntaxCopy() |
0 | 76 { |
77 Type treturn = next ? next.syntaxCopy() : null; | |
78 Arguments params = Argument.arraySyntaxCopy(parameters); | |
79 TypeFunction t = new TypeFunction(params, treturn, varargs, linkage); | |
80 t.mod = mod; | |
81 t.isnothrow = isnothrow; | |
82 t.ispure = ispure; | |
83 t.isproperty = isproperty; | |
84 t.isref = isref; | |
85 | |
86 return t; | |
87 } | |
88 | |
89 version (DumbClone) { | |
90 } else { | |
91 final TypeFunction cloneTo(TypeFunction t) | |
92 { | |
93 super.cloneTo(t); | |
94 | |
95 // these 3 should be set by ctor | |
96 assert(t.parameters is null); | |
97 assert(t.varargs == varargs); | |
98 assert(t.linkage == linkage); | |
99 | |
100 t.isnothrow = isnothrow; | |
101 t.ispure = ispure; | |
102 t.isproperty = isproperty; | |
103 t.isref = isref; | |
104 t.inuse = inuse; | |
105 | |
106 if (parameters) | |
107 { | |
108 t.parameters = parameters.copy(); | |
129 | 109 foreach (arg; parameters) |
0 | 110 { |
111 Argument cpy = arg.clone(); | |
129 | 112 t.parameters[i] = cpy; |
0 | 113 } |
114 } | |
115 | |
116 return t; | |
117 } | |
118 | |
119 TypeFunction clone() | |
120 { | |
129 | 121 assert(this.classinfo is TypeFunction.classinfo); |
0 | 122 return cloneTo(new TypeFunction(null, next, varargs, linkage)); |
123 } | |
124 } | |
72 | 125 override Type semantic(Loc loc, Scope sc) |
0 | 126 { |
127 if (deco) // if semantic() already run | |
128 { | |
129 //printf("already done\n"); | |
130 return this; | |
131 } | |
132 //printf("TypeFunction.semantic() this = %p\n", this); | |
133 //printf("TypeFunction.semantic() %s, sc.stc = %x\n", toChars(), sc.stc); | |
134 | |
135 /* Copy in order to not mess up original. | |
136 * This can produce redundant copies if inferring return type, | |
137 * as semantic() will get called again on this. | |
138 */ | |
139 | |
129 | 140 TypeFunction tf = cloneThis(this); |
0 | 141 |
142 if (sc.stc & STC.STCpure) | |
143 tf.ispure = true; | |
144 if (sc.stc & STC.STCnothrow) | |
145 tf.isnothrow = true; | |
146 if (sc.stc & STC.STCref) | |
147 tf.isref = true; | |
148 | |
149 tf.linkage = sc.linkage; | |
150 if (tf.next) | |
151 { | |
152 tf.next = tf.next.semantic(loc,sc); | |
96 | 153 version(SARRAYVALUE) {} else |
154 { | |
0 | 155 if (tf.next.toBasetype().ty == TY.Tsarray) |
129 | 156 { |
157 error(loc, "functions cannot return static array %s", tf.next.toChars()); | |
0 | 158 tf.next = Type.terror; |
159 } | |
96 | 160 } |
0 | 161 if (tf.next.toBasetype().ty == TY.Tfunction) |
129 | 162 { |
163 error(loc, "functions cannot return a function"); | |
0 | 164 tf.next = Type.terror; |
165 } | |
166 if (tf.next.toBasetype().ty == TY.Ttuple) | |
129 | 167 { |
168 error(loc, "functions cannot return a tuple"); | |
0 | 169 tf.next = Type.terror; |
170 } | |
171 if (tf.next.isauto() && !(sc.flags & SCOPE.SCOPEctor)) | |
129 | 172 error(loc, "functions cannot return scope %s", tf.next.toChars()); |
0 | 173 } |
174 | |
175 if (tf.parameters) | |
73 | 176 { |
177 /* Create a scope for evaluating the default arguments for the parameters | |
178 */ | |
179 Scope argsc = sc.push(); | |
180 argsc.stc = STCundefined; // don't inherit storage class | |
181 argsc.protection = PROT.PROTpublic; | |
182 | |
183 size_t dim = Argument.dim(tf.parameters); | |
0 | 184 |
185 for (size_t i = 0; i < dim; i++) | |
186 { Argument arg = Argument.getNth(tf.parameters, i); | |
187 | |
188 tf.inuse++; | |
73 | 189 arg.type = arg.type.semantic(loc, argsc); |
0 | 190 if (tf.inuse == 1) tf.inuse--; |
191 | |
192 arg.type = arg.type.addStorageClass(arg.storageClass); | |
193 | |
194 if (arg.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic)) | |
195 { | |
196 if (!arg.type) | |
197 continue; | |
198 } | |
199 | |
200 Type t = arg.type.toBasetype(); | |
201 | |
202 if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) | |
203 { | |
96 | 204 //if (t.ty == TY.Tsarray) |
205 //error(loc, "cannot have out or ref parameter of type %s", t.toChars()); | |
206 if (arg.storageClass & STC.STCout && arg.type.mod & (STCconst | STCimmutable)) | |
207 error(loc, "cannot have const or immutabl out parameter of type %s", t.toChars()); | |
0 | 208 } |
209 if (!(arg.storageClass & STC.STClazy) && t.ty == TY.Tvoid) | |
210 error(loc, "cannot have parameter of type %s", arg.type.toChars()); | |
211 | |
212 if (arg.defaultArg) | |
213 { | |
73 | 214 arg.defaultArg = arg.defaultArg.semantic(argsc); |
215 arg.defaultArg = resolveProperties(argsc, arg.defaultArg); | |
216 arg.defaultArg = arg.defaultArg.implicitCastTo(argsc, arg.type); | |
0 | 217 } |
218 | |
219 /* If arg turns out to be a tuple, the number of parameters may | |
220 * change. | |
221 */ | |
222 if (t.ty == TY.Ttuple) | |
223 { dim = Argument.dim(tf.parameters); | |
224 i--; | |
225 } | |
226 } | |
73 | 227 argsc.pop(); |
0 | 228 } |
229 if (tf.next) | |
230 tf.deco = tf.merge().deco; | |
231 | |
232 if (tf.inuse) | |
233 { error(loc, "recursive type"); | |
234 tf.inuse = 0; | |
235 return terror; | |
236 } | |
237 | |
238 if (tf.varargs == 1 && tf.linkage != LINK.LINKd && Argument.dim(tf.parameters) == 0) | |
239 error(loc, "variadic functions with non-D linkage must have at least one parameter"); | |
240 | |
241 /* Don't return merge(), because arg identifiers and default args | |
242 * can be different | |
243 * even though the types match | |
244 */ | |
245 return tf; | |
246 } | |
247 | |
72 | 248 override void toDecoBuffer(OutBuffer buf, int flag) |
0 | 249 { |
250 ubyte mc; | |
251 | |
252 //printf("TypeFunction.toDecoBuffer() this = %p %s\n", this, toChars()); | |
253 //static int nest; if (++nest == 50) *(char*)0=0; | |
254 if (inuse) | |
255 { | |
256 inuse = 2; // flag error to caller | |
257 return; | |
258 } | |
259 inuse++; | |
260 static if (true) { | |
261 if (mod & MOD.MODshared) | |
262 buf.writeByte('O'); | |
263 if (mod & MOD.MODconst) | |
264 buf.writeByte('x'); | |
265 else if (mod & MOD.MODinvariant) | |
266 buf.writeByte('y'); | |
267 } | |
268 switch (linkage) | |
269 { | |
270 case LINK.LINKd: mc = 'F'; break; | |
271 case LINK.LINKc: mc = 'U'; break; | |
272 case LINK.LINKwindows: mc = 'W'; break; | |
273 case LINK.LINKpascal: mc = 'V'; break; | |
274 case LINK.LINKcpp: mc = 'R'; break; | |
275 } | |
276 buf.writeByte(mc); | |
277 if (ispure || isnothrow || isproperty || isref) | |
278 { | |
279 if (ispure) | |
280 buf.writestring("Na"); | |
281 if (isnothrow) | |
282 buf.writestring("Nb"); | |
283 if (isref) | |
284 buf.writestring("Nc"); | |
285 if (isproperty) | |
286 buf.writestring("Nd"); | |
287 } | |
288 // Write argument types | |
289 Argument.argsToDecoBuffer(buf, parameters); | |
290 //if (buf.data[buf.offset - 1] == '@') halt(); | |
291 buf.writeByte('Z' - varargs); // mark end of arg list | |
79 | 292 assert(next); |
0 | 293 next.toDecoBuffer(buf); |
294 inuse--; | |
295 } | |
296 | |
72 | 297 override void toCBuffer(OutBuffer buf, Identifier ident, HdrGenState* hgs) |
0 | 298 { |
299 //printf("TypeFunction.toCBuffer() this = %p\n", this); | |
300 string p = null; | |
301 | |
302 if (inuse) | |
303 { | |
304 inuse = 2; // flag error to caller | |
305 return; | |
306 } | |
307 inuse++; | |
308 | |
309 /* Use 'storage class' style for attributes | |
310 */ | |
311 if (mod & MODconst) | |
312 buf.writestring("const "); | |
313 if (mod & MODinvariant) | |
314 buf.writestring("immutable "); | |
315 if (mod & MODshared) | |
316 buf.writestring("shared "); | |
317 | |
318 if (ispure) | |
319 buf.writestring("pure "); | |
320 if (isnothrow) | |
321 buf.writestring("nothrow "); | |
322 if (isproperty) | |
323 buf.writestring("@property "); | |
324 if (isref) | |
325 buf.writestring("ref "); | |
326 | |
327 if (next && (!ident || ident.toHChars2() == ident.toChars())) | |
328 next.toCBuffer2(buf, hgs, MODundefined); | |
329 if (hgs.ddoc != 1) | |
330 { | |
331 switch (linkage) | |
332 { | |
333 case LINKd: p = null; break; | |
73 | 334 case LINKc: p = " C"; break; |
335 case LINKwindows: p = " Windows"; break; | |
336 case LINKpascal: p = " Pascal"; break; | |
337 case LINKcpp: p = " C++"; break; | |
0 | 338 default: |
339 assert(0); | |
340 } | |
341 } | |
342 | |
343 if (!hgs.hdrgen && p) | |
344 buf.writestring(p); | |
345 if (ident) | |
346 { | |
347 buf.writeByte(' '); | |
348 buf.writestring(ident.toHChars2()); | |
349 } | |
350 Argument.argsToCBuffer(buf, hgs, parameters, varargs); | |
351 inuse--; | |
352 } | |
353 | |
72 | 354 override void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) |
0 | 355 { |
356 //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); | |
357 string p; | |
358 | |
359 if (inuse) | |
360 { | |
361 inuse = 2; // flag error to caller | |
362 return; | |
363 } | |
364 | |
365 inuse++; | |
366 if (next) | |
367 next.toCBuffer2(buf, hgs, MODundefined); | |
368 | |
369 if (hgs.ddoc != 1) | |
370 { | |
371 switch (linkage) | |
372 { | |
373 case LINKd: p = null; break; | |
374 case LINKc: p = "C "; break; | |
375 case LINKwindows: p = "Windows "; break; | |
376 case LINKpascal: p = "Pascal "; break; | |
377 case LINKcpp: p = "C++ "; break; | |
378 default: assert(0); | |
379 } | |
380 } | |
381 | |
382 if (!hgs.hdrgen && p) | |
383 buf.writestring(p); | |
384 buf.writestring(" function"); | |
385 Argument.argsToCBuffer(buf, hgs, parameters, varargs); | |
386 | |
387 /* Use postfix style for attributes | |
388 */ | |
389 if (mod != this.mod) | |
390 { | |
391 modToBuffer(buf); | |
392 } | |
393 | |
394 if (ispure) | |
395 buf.writestring(" pure"); | |
396 if (isnothrow) | |
397 buf.writestring(" nothrow"); | |
398 if (isproperty) | |
399 buf.writestring(" @property"); | |
400 if (isref) | |
401 buf.writestring(" ref"); | |
402 | |
403 inuse--; | |
404 } | |
405 | |
72 | 406 override MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) |
0 | 407 { |
123 | 408 //printf("TypeFunction.deduceType()\n"); |
409 //printf("\tthis = %d, ", ty); print(); | |
410 //printf("\ttparam = %d, ", tparam.ty); tparam.print(); | |
411 | |
412 // Extra check that function characteristics must match | |
413 if (tparam && tparam.ty == Tfunction) | |
414 { | |
415 TypeFunction tp = cast(TypeFunction)tparam; | |
416 if (varargs != tp.varargs || | |
417 linkage != tp.linkage) | |
418 return MATCHnomatch; | |
419 | |
420 size_t nfargs = Argument.dim(this.parameters); | |
421 size_t nfparams = Argument.dim(tp.parameters); | |
422 | |
423 /* See if tuple match | |
424 */ | |
425 if (nfparams > 0 && nfargs >= nfparams - 1) | |
426 { | |
427 /* See if 'A' of the template parameter matches 'A' | |
428 * of the type of the last function parameter. | |
429 */ | |
430 Argument fparam = Argument.getNth(tp.parameters, nfparams - 1); | |
431 assert(fparam); | |
432 assert(fparam.type); | |
433 if (fparam.type.ty != Tident) | |
434 goto L1; | |
435 TypeIdentifier tid = cast(TypeIdentifier)fparam.type; | |
436 if (tid.idents.dim) | |
437 goto L1; | |
438 | |
439 /* Look through parameters to find tuple matching tid.ident | |
440 */ | |
441 size_t tupi = 0; | |
442 for (; 1; tupi++) | |
443 { | |
444 if (tupi == parameters.dim) | |
445 goto L1; | |
446 TemplateParameter t = parameters[tupi]; | |
447 TemplateTupleParameter tup = t.isTemplateTupleParameter(); | |
448 if (tup && tup.ident.equals(tid.ident)) | |
449 break; | |
450 } | |
451 | |
452 /* The types of the function arguments [nfparams - 1 .. nfargs] | |
453 * now form the tuple argument. | |
454 */ | |
455 int tuple_dim = nfargs - (nfparams - 1); | |
456 | |
457 /* See if existing tuple, and whether it matches or not | |
458 */ | |
459 Object o = dedtypes[tupi]; | |
460 if (o) | |
461 { | |
462 // Existing deduced argument must be a tuple, and must match | |
463 Tuple t = isTuple(o); | |
464 if (!t || t.objects.dim != tuple_dim) | |
465 return MATCHnomatch; | |
466 for (size_t i = 0; i < tuple_dim; i++) | |
467 { | |
468 Argument arg = Argument.getNth(this.parameters, nfparams - 1 + i); | |
469 if (!arg.type.equals(t.objects[i])) | |
470 return MATCHnomatch; | |
471 } | |
472 } | |
473 else | |
474 { // Create new tuple | |
475 Tuple t = new Tuple(); | |
476 t.objects.setDim(tuple_dim); | |
477 for (size_t i = 0; i < tuple_dim; i++) | |
478 { | |
479 Argument arg = Argument.getNth(this.parameters, nfparams - 1 + i); | |
480 t.objects[i] = arg.type; | |
481 } | |
482 dedtypes[tupi] = t; | |
483 } | |
484 nfparams--; // don't consider the last parameter for type deduction | |
485 goto L2; | |
486 } | |
487 | |
488 L1: | |
489 if (nfargs != nfparams) | |
490 return MATCHnomatch; | |
491 L2: | |
492 for (size_t i = 0; i < nfparams; i++) | |
493 { | |
494 Argument a = Argument.getNth(this.parameters, i); | |
495 Argument ap = Argument.getNth(tp.parameters, i); | |
496 if (a.storageClass != ap.storageClass || | |
497 !a.type.deduceType(sc, ap.type, parameters, dedtypes)) | |
498 return MATCHnomatch; | |
499 } | |
500 } | |
501 return Type.deduceType(sc, tparam, parameters, dedtypes); | |
0 | 502 } |
503 | |
72 | 504 override TypeInfoDeclaration getTypeInfoDeclaration() |
0 | 505 { |
129 | 506 return new TypeInfoFunctionDeclaration(this); |
0 | 507 } |
508 | |
72 | 509 override Type reliesOnTident() |
0 | 510 { |
511 if (parameters) | |
512 { | |
126
1765f3ef917d
ClassDeclarations, Arguments -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
513 foreach (arg; parameters) |
0 | 514 { |
515 Type t = arg.type.reliesOnTident(); | |
516 if (t) | |
517 return t; | |
518 } | |
519 } | |
520 return next.reliesOnTident(); | |
521 } | |
522 | |
523 version (CPP_MANGLE) { | |
524 void toCppMangle(OutBuffer buf, CppMangleState* cms) | |
525 { | |
526 assert(false); | |
527 } | |
528 } | |
529 | |
530 /*************************** | |
531 * Examine function signature for parameter p and see if | |
532 * p can 'escape' the scope of the function. | |
533 */ | |
534 bool parameterEscapes(Argument p) | |
535 { | |
536 /* Scope parameters do not escape. | |
537 * Allow 'lazy' to imply 'scope' - | |
538 * lazy parameters can be passed along | |
539 * as lazy parameters to the next function, but that isn't | |
540 * escaping. | |
541 */ | |
542 if (p.storageClass & (STC.STCscope | STC.STClazy)) | |
543 return false; | |
544 | |
545 if (ispure) | |
546 { /* With pure functions, we need only be concerned if p escapes | |
547 * via any return statement. | |
548 */ | |
549 Type tret = nextOf().toBasetype(); | |
550 if (!isref && !tret.hasPointers()) | |
551 { /* The result has no references, so p could not be escaping | |
552 * that way. | |
553 */ | |
554 return false; | |
555 } | |
556 } | |
557 | |
558 /* Assume it escapes in the absence of better information. | |
559 */ | |
560 return true; | |
561 } | |
562 | |
563 /******************************** | |
564 * 'args' are being matched to function 'this' | |
565 * Determine match level. | |
566 * Returns: | |
567 * MATCHxxxx | |
568 */ | |
569 MATCH callMatch(Expression ethis, Expressions args) | |
570 { | |
571 //printf("TypeFunction.callMatch() %s\n", toChars()); | |
572 MATCH match = MATCH.MATCHexact; // assume exact match | |
573 | |
574 if (ethis) | |
575 { | |
576 Type t = ethis.type; | |
577 if (t.toBasetype().ty == TY.Tpointer) | |
578 t = t.toBasetype().nextOf(); // change struct* to struct | |
579 | |
580 if (t.mod != mod) | |
581 { | |
582 if (mod == MOD.MODconst) | |
583 match = MATCH.MATCHconst; | |
584 else | |
585 return MATCH.MATCHnomatch; | |
586 } | |
587 } | |
588 | |
589 size_t nparams = Argument.dim(parameters); | |
590 size_t nargs = args ? args.dim : 0; | |
591 if (nparams == nargs) { | |
592 ; | |
593 } else if (nargs > nparams) | |
594 { | |
595 if (varargs == 0) | |
596 goto Nomatch; // too many args; no match | |
597 match = MATCH.MATCHconvert; // match ... with a "conversion" match level | |
598 } | |
599 | |
600 for (size_t u = 0; u < nparams; u++) | |
601 { | |
602 MATCH m; | |
603 Expression arg; | |
604 | |
605 // BUG: what about out and ref? | |
606 | |
607 Argument p = Argument.getNth(parameters, u); | |
608 assert(p); | |
609 if (u >= nargs) | |
610 { | |
611 if (p.defaultArg) | |
612 continue; | |
613 if (varargs == 2 && u + 1 == nparams) | |
614 goto L1; | |
615 goto Nomatch; // not enough arguments | |
616 } | |
617 | |
113
3482c73a991b
More cleanup for arrays
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
96
diff
changeset
|
618 arg = cast(Expression)args[u]; |
0 | 619 assert(arg); |
96 | 620 // writef("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); |
621 | |
0 | 622 |
623 // Non-lvalues do not match ref or out parameters | |
96 | 624 if (p.storageClass & (STC.STCref | STC.STCout)) |
625 { | |
626 if (!arg.isLvalue()) | |
627 goto Nomatch; | |
628 } | |
629 | |
630 if (p.storageClass & STCref) | |
631 { | |
632 /* Don't allow static arrays to be passed to mutable refereces | |
633 * to static arrays if the argument cannot be modified. | |
634 */ | |
635 Type targb = arg.type.toBasetype(); | |
636 Type tparb = p.type.toBasetype(); | |
637 //writef("%s\n", targb.toChars()); | |
638 //writef("%s\n", tparb.toChars()); | |
639 if (targb.nextOf() && tparb.ty == Tsarray && | |
640 targb.nextOf().mod != tparb.nextOf().mod && | |
641 !tparb.nextOf().isConst()) | |
642 goto Nomatch; | |
643 } | |
0 | 644 |
645 if (p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid && arg.type.ty != TY.Tvoid) | |
646 m = MATCH.MATCHconvert; | |
647 else | |
648 m = arg.implicitConvTo(p.type); | |
649 //printf("\tm = %d\n", m); | |
650 if (m == MATCH.MATCHnomatch) // if no match | |
651 { | |
652 L1: | |
653 if (varargs == 2 && u + 1 == nparams) // if last varargs param | |
654 { | |
655 Type tb = p.type.toBasetype(); | |
656 TypeSArray tsa; | |
657 long sz; | |
658 | |
659 switch (tb.ty) | |
660 { | |
661 case TY.Tsarray: | |
662 tsa = cast(TypeSArray)tb; | |
663 sz = tsa.dim.toInteger(); | |
664 if (sz != nargs - u) | |
665 goto Nomatch; | |
666 case TY.Tarray: | |
667 { | |
668 TypeArray ta = cast(TypeArray)tb; | |
669 for (; u < nargs; u++) | |
670 { | |
113
3482c73a991b
More cleanup for arrays
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
96
diff
changeset
|
671 arg = cast(Expression)args[u]; |
0 | 672 assert(arg); |
673 static if (true) { | |
674 /* If lazy array of delegates, | |
675 * convert arg(s) to delegate(s) | |
676 */ | |
677 Type tret = p.isLazyArray(); | |
678 if (tret) | |
679 { | |
680 if (ta.next.equals(arg.type)) | |
681 { | |
682 m = MATCH.MATCHexact; | |
683 } | |
684 else | |
685 { | |
686 m = arg.implicitConvTo(tret); | |
687 if (m == MATCH.MATCHnomatch) | |
688 { | |
689 if (tret.toBasetype().ty == TY.Tvoid) | |
690 m = MATCH.MATCHconvert; | |
691 } | |
692 } | |
693 } | |
694 else | |
695 m = arg.implicitConvTo(ta.next); | |
696 } else { | |
697 m = arg.implicitConvTo(ta.next); | |
698 } | |
699 if (m == MATCH.MATCHnomatch) | |
700 goto Nomatch; | |
701 | |
702 if (m < match) | |
703 match = m; | |
704 } | |
705 goto Ldone; | |
706 } | |
707 | |
708 case TY.Tclass: | |
709 // Should see if there's a constructor match? | |
710 // Or just leave it ambiguous? | |
711 goto Ldone; | |
712 | |
713 default: | |
714 goto Nomatch; | |
715 } | |
716 } | |
717 | |
718 goto Nomatch; | |
719 } | |
720 | |
721 if (m < match) | |
722 match = m; // pick worst match | |
723 } | |
724 | |
725 Ldone: | |
726 //printf("match = %d\n", match); | |
727 return match; | |
728 | |
729 Nomatch: | |
730 //printf("no match\n"); | |
731 return MATCH.MATCHnomatch; | |
732 } | |
733 | |
96 | 734 override type* toCtype() |
0 | 735 { |
736 if (ctype) { | |
737 return ctype; | |
738 } | |
739 | |
740 type* t; | |
741 if (true) | |
742 { | |
743 param_t* paramtypes; | |
744 tym_t tyf; | |
745 type* tp; | |
746 | |
747 paramtypes = null; | |
748 size_t nparams = Argument.dim(parameters); | |
749 for (size_t i = 0; i < nparams; i++) | |
750 { | |
751 Argument arg = Argument.getNth(parameters, i); | |
752 tp = arg.type.toCtype(); | |
753 if (arg.storageClass & (STC.STCout | STC.STCref)) | |
754 { | |
755 // C doesn't have reference types, so it's really a pointer | |
756 // to the parameter type | |
757 tp = type_allocn(TYM.TYref, tp); | |
758 } | |
759 param_append_type(¶mtypes,tp); | |
760 } | |
761 tyf = totym(); | |
762 t = type_alloc(tyf); | |
763 t.Tflags |= TF.TFprototype; | |
764 if (varargs != 1) | |
765 t.Tflags |= TF.TFfixed; | |
766 ctype = t; | |
767 t.Tnext = next.toCtype(); | |
768 t.Tnext.Tcount++; | |
769 t.Tparamtypes = paramtypes; | |
770 } | |
771 ctype = t; | |
772 return t; | |
773 } | |
774 | |
775 /*************************** | |
776 * Determine return style of function - whether in registers or | |
777 * through a hidden pointer to the caller's stack. | |
778 */ | |
96 | 779 RET retStyle() |
0 | 780 { |
781 //printf("TypeFunction.retStyle() %s\n", toChars()); | |
95 | 782 version (DMDV2) |
783 { | |
0 | 784 if (isref) |
785 return RET.RETregs; // returns a pointer | |
786 } | |
787 | |
788 Type tn = next.toBasetype(); | |
95 | 789 Type tns = tn; |
790 ulong sz = tn.size(); | |
0 | 791 |
95 | 792 version(SARRAYVALUE) |
793 { | |
794 if (tn.ty == Tsarray) | |
795 { | |
796 do | |
797 { | |
798 tns = tns.nextOf().toBasetype(); | |
799 } while (tns.ty == Tsarray); | |
800 if (tns.ty != Tstruct) | |
801 { | |
802 if (global.params.isLinux && linkage != LINKd) | |
803 {} | |
804 else | |
805 { | |
806 switch (sz) | |
807 { case 1: | |
808 case 2: | |
809 case 4: | |
810 case 8: | |
96 | 811 return RET.RETregs; // return small structs in regs |
812 // (not 3 byte structs!) | |
95 | 813 default: |
814 break; | |
815 } | |
816 } | |
96 | 817 return RET.RETstack; |
95 | 818 } |
819 } | |
820 } | |
821 if (tns.ty == TY.Tstruct) | |
0 | 822 { |
823 StructDeclaration sd = (cast(TypeStruct)tn).sym; | |
824 if (global.params.isLinux && linkage != LINK.LINKd) { | |
825 ; | |
826 } | |
95 | 827 ///version (DMDV2) { // TODO: |
828 else if (sd.dtor || sd.cpctor) | |
829 { | |
0 | 830 } |
831 ///} | |
832 else | |
833 { | |
95 | 834 switch (sz) |
0 | 835 { |
836 case 1: | |
837 case 2: | |
838 case 4: | |
839 case 8: | |
840 return RET.RETregs; // return small structs in regs | |
841 // (not 3 byte structs!) | |
842 default: | |
843 break; | |
844 } | |
845 } | |
846 return RET.RETstack; | |
847 } | |
848 else if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && | |
849 linkage == LINK.LINKc && | |
850 tn.iscomplex()) | |
851 { | |
852 if (tn.ty == TY.Tcomplex32) | |
853 return RET.RETregs; // in EDX:EAX, not ST1:ST0 | |
854 else | |
855 return RET.RETstack; | |
856 } | |
857 else | |
858 return RET.RETregs; | |
859 } | |
860 | |
72 | 861 override TYM totym() |
0 | 862 { |
863 TYM tyf; | |
864 | |
865 //printf("TypeFunction.totym(), linkage = %d\n", linkage); | |
866 switch (linkage) | |
867 { | |
868 case LINK.LINKwindows: | |
869 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnsfunc; | |
870 break; | |
871 | |
872 case LINK.LINKpascal: | |
873 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYnpfunc; | |
874 break; | |
875 | |
876 case LINK.LINKc: | |
877 tyf = TYM.TYnfunc; | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
878 version (POSIX) {///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS |
0 | 879 if (retStyle() == RET.RETstack) |
880 tyf = TYM.TYhfunc; | |
881 } | |
882 break; | |
883 | |
884 case LINK.LINKd: | |
885 tyf = (varargs == 1) ? TYM.TYnfunc : TYM.TYjfunc; | |
886 break; | |
887 | |
888 case LINK.LINKcpp: | |
889 tyf = TYM.TYnfunc; | |
890 break; | |
891 | |
892 default: | |
893 writef("linkage = %d\n", linkage); | |
894 assert(0); | |
895 } | |
896 version (DMDV2) { | |
897 if (isnothrow) | |
898 tyf |= mTY.mTYnothrow; | |
899 } | |
900 return tyf; | |
901 } | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
902 } |