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