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