Mercurial > projects > ddmd
annotate dmd/FuncDeclaration.d @ 14:2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Sun, 04 Apr 2010 02:06:32 +0100 |
parents | 10317f0c89a5 |
children | ddae60498573 |
rev | line source |
---|---|
0 | 1 module dmd.FuncDeclaration; |
2 | |
3 import dmd.Declaration; | |
4 import dmd.DotIdExp; | |
5 import dmd.TryFinallyStatement; | |
6 import dmd.StaticDtorDeclaration; | |
7 import dmd.PeelStatement; | |
8 import dmd.SynchronizedStatement; | |
9 import dmd.TOK; | |
10 import dmd.SymOffExp; | |
11 import dmd.AssignExp; | |
12 import dmd.ExpInitializer; | |
13 import dmd.BE; | |
14 import dmd.Id; | |
15 import dmd.StringExp; | |
16 import dmd.DsymbolExp; | |
17 import dmd.HaltExp; | |
18 import dmd.CommaExp; | |
19 import dmd.ReturnStatement; | |
20 import dmd.IntegerExp; | |
21 import dmd.ExpStatement; | |
22 import dmd.CSX; | |
23 import dmd.CompoundStatement; | |
24 import dmd.LabelStatement; | |
25 import dmd.ThisExp; | |
26 import dmd.SuperExp; | |
27 import dmd.IdentifierExp; | |
28 import dmd.AssertExp; | |
29 import dmd.CallExp; | |
30 import dmd.RET; | |
31 import dmd.VarExp; | |
32 import dmd.TupleDeclaration; | |
33 import dmd.ThisDeclaration; | |
34 import dmd.TypeTuple; | |
35 import dmd.TemplateInstance; | |
36 import dmd.ScopeDsymbol; | |
37 import dmd.AliasDeclaration; | |
38 import dmd.MOD; | |
39 import dmd.PROT; | |
40 import dmd.Lexer; | |
41 import dmd.LINK; | |
42 import dmd.CtorDeclaration; | |
43 import dmd.Global; | |
44 import dmd.DtorDeclaration; | |
45 import dmd.InvariantDeclaration; | |
46 import dmd.TY; | |
47 import dmd.PtrExp; | |
48 import dmd.DeclarationExp; | |
49 import dmd.InlineDoState; | |
50 import dmd.Argument; | |
51 import dmd.StructDeclaration; | |
52 import dmd.ClassDeclaration; | |
53 import dmd.InterfaceDeclaration; | |
54 import dmd.Array; | |
55 import dmd.Statement; | |
56 import dmd.Identifier; | |
57 import dmd.VarDeclaration; | |
58 import dmd.LabelDsymbol; | |
59 import dmd.DsymbolTable; | |
60 import dmd.ArrayTypes; | |
61 import dmd.Loc; | |
62 import dmd.ILS; | |
63 import dmd.ForeachStatement; | |
64 import dmd.Type; | |
65 import dmd.BUILTIN; | |
66 import dmd.TypeFunction; | |
67 import dmd.Expression; | |
68 import dmd.STC; | |
69 import dmd.Dsymbol; | |
70 import dmd.Scope; | |
71 import dmd.OutBuffer; | |
72 import dmd.HdrGenState; | |
73 import dmd.MATCH; | |
74 import dmd.AggregateDeclaration; | |
75 import dmd.InterState; | |
76 import dmd.InlineScanState; | |
77 import dmd.IRState; | |
78 import dmd.Util; | |
79 import dmd.BaseClass; | |
80 import dmd.Module; | |
81 import dmd.ILS; | |
82 import dmd.InlineCostState; | |
83 | |
84 import dmd.expression.Util; | |
85 | |
86 import dmd.declaration.Match; | |
87 | |
88 import dmd.backend.Symbol; | |
89 import dmd.backend.func_t; | |
90 import dmd.backend.Util; | |
91 import dmd.backend.glue; | |
92 import dmd.backend.SC; | |
93 import dmd.backend.F; | |
94 import dmd.backend.Cstate; | |
95 import dmd.backend.TYM; | |
96 import dmd.backend.OPER; | |
97 import dmd.backend.TYFL; | |
98 import dmd.backend.TYPE; | |
99 import dmd.backend.SFL; | |
100 import dmd.backend.mTY; | |
101 import dmd.backend.FL; | |
102 import dmd.backend.REG; | |
103 import dmd.backend.block; | |
104 import dmd.backend.Blockx; | |
105 import dmd.backend.Config; | |
106 import dmd.backend.BC; | |
107 import dmd.backend.elem; | |
108 import dmd.backend.targ_types; | |
109 import dmd.backend.mTYman; | |
110 import dmd.backend.RTLSYM; | |
111 import dmd.backend.LIST; | |
112 | |
113 import core.stdc.stdio; | |
114 import core.stdc.string; | |
14
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
115 version (Bug4054) import core.memory; |
0 | 116 |
117 import std.string; | |
118 | |
119 class FuncDeclaration : Declaration | |
120 { | |
121 Array fthrows; // Array of Type's of exceptions (not used) | |
122 Statement frequire; | |
123 Statement fensure; | |
124 Statement fbody; | |
125 | |
126 Identifier outId; // identifier for out statement | |
127 VarDeclaration vresult; // variable corresponding to outId | |
128 LabelDsymbol returnLabel; // where the return goes | |
129 | |
130 DsymbolTable localsymtab; // used to prevent symbols in different | |
131 // scopes from having the same name | |
132 VarDeclaration vthis; // 'this' parameter (member and nested) | |
133 VarDeclaration v_arguments; // '_arguments' parameter | |
134 version (IN_GCC) { | |
135 VarDeclaration v_argptr; // '_argptr' variable | |
136 } | |
137 Dsymbols parameters; // Array of VarDeclaration's for parameters | |
138 DsymbolTable labtab; // statement label symbol table | |
139 Declaration overnext; // next in overload list | |
140 Loc endloc; // location of closing curly bracket | |
141 int vtblIndex = -1; // for member functions, index into vtbl[] | |
142 int naked; // !=0 if naked | |
143 int inlineAsm; // !=0 if has inline assembler | |
144 ILS inlineStatus = ILS.ILSuninitialized; | |
145 int inlineNest; // !=0 if nested inline | |
146 int cantInterpret; // !=0 if cannot interpret function | |
147 int semanticRun; // 1 semantic() run | |
148 // 2 semantic2() run | |
149 // 3 semantic3() started | |
150 // 4 semantic3() done | |
151 // 5 toObjFile() run | |
152 // this function's frame ptr | |
153 ForeachStatement fes; // if foreach body, this is the foreach | |
154 int introducing; // !=0 if 'introducing' function | |
155 Type tintro; // if !=null, then this is the type | |
156 // of the 'introducing' function | |
157 // this one is overriding | |
158 int inferRetType; // !=0 if return type is to be inferred | |
159 | |
160 // Things that should really go into Scope | |
161 int hasReturnExp; // 1 if there's a return exp; statement | |
162 // 2 if there's a throw statement | |
163 // 4 if there's an assert(0) | |
164 // 8 if there's inline asm | |
165 | |
166 // Support for NRVO (named return value optimization) | |
167 bool nrvo_can = true; // !=0 means we can do it | |
168 VarDeclaration nrvo_var; // variable to replace with shidden | |
169 Symbol* shidden; // hidden pointer passed to function | |
170 | |
171 version (DMDV2) { | |
172 BUILTIN builtin; // set if this is a known, builtin | |
173 // function we can evaluate at compile | |
174 // time | |
175 | |
176 int tookAddressOf; // set if someone took the address of | |
177 // this function | |
178 Dsymbols closureVars; // local variables in this function | |
179 // which are referenced by nested | |
180 // functions | |
181 } else { | |
182 int nestedFrameRef; // !=0 if nested variables referenced | |
183 } | |
184 | |
185 this(Loc loc, Loc endloc, Identifier id, STC storage_class, Type type) | |
186 { | |
187 super(id); | |
188 | |
189 //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type); | |
190 //printf("storage_class = x%x\n", storage_class); | |
191 this.storage_class = storage_class; | |
192 this.type = type; | |
193 this.loc = loc; | |
194 this.endloc = endloc; | |
195 | |
196 /* The type given for "infer the return type" is a TypeFunction with | |
197 * null for the return type. | |
198 */ | |
199 inferRetType = (type && type.nextOf() is null); | |
200 | |
201 closureVars = new Dsymbols(); | |
202 | |
203 version (DMDV2) { | |
204 builtin = BUILTIN.BUILTINunknown; | |
205 } | |
206 } | |
207 | |
208 Dsymbol syntaxCopy(Dsymbol s) | |
209 { | |
210 FuncDeclaration f; | |
211 | |
212 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); | |
213 if (s) | |
214 f = cast(FuncDeclaration)s; | |
215 else | |
216 f = new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy()); | |
217 | |
218 f.outId = outId; | |
219 f.frequire = frequire ? frequire.syntaxCopy() : null; | |
220 f.fensure = fensure ? fensure.syntaxCopy() : null; | |
221 f.fbody = fbody ? fbody.syntaxCopy() : null; | |
222 assert(!fthrows); // deprecated | |
223 | |
224 return f; | |
225 } | |
226 | |
227 // Do the semantic analysis on the external interface to the function. | |
228 void semantic(Scope sc) | |
229 { | |
230 TypeFunction f; | |
231 StructDeclaration sd; | |
232 ClassDeclaration cd; | |
233 InterfaceDeclaration id; | |
234 Dsymbol pd; | |
235 | |
236 static if (false) { | |
237 printf("FuncDeclaration.semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc.linkage); | |
238 if (isFuncLiteralDeclaration()) | |
239 printf("\tFuncLiteralDeclaration()\n"); | |
240 printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), parent ? parent.toChars() : ""); | |
241 printf("type: %p, %s\n", type, type.toChars()); | |
242 } | |
243 | |
244 if (semanticRun && isFuncLiteralDeclaration()) | |
245 { | |
246 /* Member functions that have return types that are | |
247 * forward references can have semantic() run more than | |
248 * once on them. | |
249 * See test\interface2.d, test20 | |
250 */ | |
251 return; | |
252 } | |
253 assert(semanticRun <= 1); | |
254 semanticRun = 1; | |
255 | |
256 storage_class |= sc.stc & ~STC.STCref; | |
257 //printf("function storage_class = x%x\n", storage_class); | |
258 | |
259 if (!originalType) | |
260 originalType = type; | |
261 if (!type.deco) | |
262 { | |
263 /* Apply const and invariant storage class | |
264 * to the function type | |
265 */ | |
266 type = type.semantic(loc, sc); | |
267 STC stc = storage_class; | |
268 if (type.isInvariant()) | |
269 stc |= STC.STCimmutable; | |
270 if (type.isConst()) | |
271 stc |= STC.STCconst; | |
272 if (type.isShared() || storage_class & STC.STCsynchronized) | |
273 stc |= STC.STCshared; | |
274 switch (stc & STC.STC_TYPECTOR) | |
275 { | |
276 case STC.STCimmutable: | |
277 case STC.STCimmutable | STC.STCconst: | |
278 case STC.STCimmutable | STC.STCconst | STC.STCshared: | |
279 case STC.STCimmutable | STC.STCshared: | |
280 // Don't use toInvariant(), as that will do a merge() | |
281 type = type.makeInvariant(); | |
282 type.deco = type.merge().deco; | |
283 break; | |
284 | |
285 case STC.STCconst: | |
286 type = type.makeConst(); | |
287 type.deco = type.merge().deco; | |
288 break; | |
289 | |
290 case STC.STCshared | STC.STCconst: | |
291 type = type.makeSharedConst(); | |
292 type.deco = type.merge().deco; | |
293 break; | |
294 | |
295 case STC.STCshared: | |
296 type = type.makeShared(); | |
297 type.deco = type.merge().deco; | |
298 break; | |
299 | |
300 case STC.STCundefined: | |
301 break; | |
302 | |
303 default: | |
304 assert(0); | |
305 } | |
306 } | |
307 //type.print(); | |
308 if (type.ty != TY.Tfunction) | |
309 { | |
310 error("%s must be a function", toChars()); | |
311 return; | |
312 } | |
313 f = cast(TypeFunction)type; | |
314 size_t nparams = Argument.dim(f.parameters); | |
315 | |
316 linkage = sc.linkage; | |
317 // if (!parent) | |
318 { | |
319 //parent = sc.scopesym; | |
320 parent = sc.parent; | |
321 } | |
322 protection = sc.protection; | |
323 Dsymbol parent = toParent(); | |
324 | |
325 if (storage_class & STC.STCscope) | |
326 error("functions cannot be scope"); | |
327 | |
328 if (isAbstract() && !isVirtual()) | |
329 error("non-virtual functions cannot be abstract"); | |
330 | |
331 if ((f.isConst() || f.isInvariant()) && !isThis()) | |
332 error("without 'this' cannot be const/immutable"); | |
333 | |
334 if (isAbstract() && isFinal()) | |
335 error("cannot be both final and abstract"); | |
336 static if (false) { | |
337 if (isAbstract() && fbody) | |
338 error("abstract functions cannot have bodies"); | |
339 } | |
340 | |
341 static if (false) { | |
342 if (isStaticConstructor() || isStaticDestructor()) | |
343 { | |
344 if (!isStatic() || type.nextOf().ty != Tvoid) | |
345 error("static constructors / destructors must be static void"); | |
346 if (f.arguments && f.arguments.dim) | |
347 error("static constructors / destructors must have empty parameter list"); | |
348 // BUG: check for invalid storage classes | |
349 } | |
350 } | |
351 | |
352 version (IN_GCC) { | |
353 AggregateDeclaration ad; | |
354 | |
355 ad = parent.isAggregateDeclaration(); | |
356 if (ad) | |
357 ad.methods.push(cast(void*)this); | |
358 } | |
359 sd = parent.isStructDeclaration(); | |
360 if (sd) | |
361 { | |
362 if (isCtorDeclaration()) | |
363 { | |
364 return; | |
365 } | |
366 static if (false) { | |
367 // Verify no constructors, destructors, etc. | |
368 if (isCtorDeclaration() | |
369 //||isDtorDeclaration() | |
370 //|| isInvariantDeclaration() | |
371 //|| isUnitTestDeclaration() | |
372 ) | |
373 { | |
374 error("special member functions not allowed for %ss", sd.kind()); | |
375 } | |
376 | |
377 if (!sd.inv) | |
378 sd.inv = isInvariantDeclaration(); | |
379 | |
380 if (!sd.aggNew) | |
381 sd.aggNew = isNewDeclaration(); | |
382 | |
383 if (isDelete()) | |
384 { | |
385 if (sd.aggDelete) | |
386 error("multiple delete's for struct %s", sd.toChars()); | |
387 sd.aggDelete = cast(DeleteDeclaration)this; | |
388 } | |
389 } | |
390 } | |
391 | |
392 id = parent.isInterfaceDeclaration(); | |
393 if (id) | |
394 { | |
395 storage_class |= STC.STCabstract; | |
396 | |
397 if (isCtorDeclaration() || | |
398 ///static if (DMDV2) { | |
399 isPostBlitDeclaration() || | |
400 ///} | |
401 isDtorDeclaration() || | |
402 isInvariantDeclaration() || | |
403 isUnitTestDeclaration() || isNewDeclaration() || isDelete()) | |
404 error("special function not allowed in interface %s", id.toChars()); | |
405 if (fbody) | |
406 error("function body is not abstract in interface %s", id.toChars()); | |
407 } | |
408 | |
409 /* Template member functions aren't virtual: | |
410 * interface TestInterface { void tpl(T)(); } | |
411 * and so won't work in interfaces | |
412 */ | |
413 if ((pd = toParent()) !is null && | |
414 pd.isTemplateInstance() && | |
415 (pd = toParent2()) !is null && | |
416 (id = pd.isInterfaceDeclaration()) !is null) | |
417 { | |
418 error("template member function not allowed in interface %s", id.toChars()); | |
419 } | |
420 | |
421 cd = parent.isClassDeclaration(); | |
422 if (cd) | |
423 { int vi; | |
424 CtorDeclaration ctor; | |
425 DtorDeclaration dtor; | |
426 InvariantDeclaration inv; | |
427 | |
428 if (isCtorDeclaration()) | |
429 { | |
430 // ctor = cast(CtorDeclaration)this; | |
431 // if (!cd.ctor) | |
432 // cd.ctor = ctor; | |
433 return; | |
434 } | |
435 | |
436 static if (false) { | |
437 dtor = isDtorDeclaration(); | |
438 if (dtor) | |
439 { | |
440 if (cd.dtor) | |
441 error("multiple destructors for class %s", cd.toChars()); | |
442 cd.dtor = dtor; | |
443 } | |
444 | |
445 inv = isInvariantDeclaration(); | |
446 if (inv) | |
447 { | |
448 cd.inv = inv; | |
449 } | |
450 | |
451 if (isNewDeclaration()) | |
452 { | |
453 if (!cd.aggNew) | |
454 cd.aggNew = cast(NewDeclaration)this; | |
455 } | |
456 | |
457 if (isDelete()) | |
458 { | |
459 if (cd.aggDelete) | |
460 error("multiple delete's for class %s", cd.toChars()); | |
461 cd.aggDelete = cast(DeleteDeclaration)this; | |
462 } | |
463 } | |
464 | |
465 if (storage_class & STC.STCabstract) | |
466 cd.isabstract = true; | |
467 | |
468 // if static function, do not put in vtbl[] | |
469 if (!isVirtual()) | |
470 { | |
471 //printf("\tnot virtual\n"); | |
472 goto Ldone; | |
473 } | |
474 | |
475 // Find index of existing function in vtbl[] to override | |
476 vi = findVtblIndex(cd.vtbl, cd.baseClass ? cd.baseClass.vtbl.dim : 0); | |
477 switch (vi) | |
478 { | |
479 case -1: | |
480 /* Didn't find one, so | |
481 * This is an 'introducing' function which gets a new | |
482 * slot in the vtbl[]. | |
483 */ | |
484 | |
485 // Verify this doesn't override previous final function | |
486 if (cd.baseClass) | |
487 { | |
488 Dsymbol s = cd.baseClass.search(loc, ident, 0); | |
489 if (s) | |
490 { | |
491 FuncDeclaration ff = s.isFuncDeclaration(); | |
492 ff = ff.overloadExactMatch(type); | |
493 if (ff && ff.isFinal() && ff.prot() != PROT.PROTprivate) | |
494 error("cannot override final function %s", ff.toPrettyChars()); | |
495 } | |
496 } | |
497 | |
498 if (isFinal()) | |
499 { | |
500 if (isOverride()) | |
501 error("does not override any function"); | |
502 cd.vtblFinal.push(cast(void*)this); | |
503 } | |
504 else | |
505 { | |
506 // Append to end of vtbl[] | |
507 //printf("\tintroducing function\n"); | |
508 introducing = 1; | |
509 vi = cd.vtbl.dim; | |
510 cd.vtbl.push(cast(void*)this); | |
511 vtblIndex = vi; | |
512 } | |
513 break; | |
514 | |
515 case -2: // can't determine because of fwd refs | |
516 cd.sizeok = 2; // can't finish due to forward reference | |
517 return; | |
518 | |
519 default: | |
520 { | |
521 FuncDeclaration fdv = cast(FuncDeclaration)cd.vtbl.data[vi]; | |
522 // This function is covariant with fdv | |
523 if (fdv.isFinal()) | |
524 error("cannot override final function %s", fdv.toPrettyChars()); | |
525 | |
526 version (DMDV2) { | |
527 if (!isOverride()) | |
528 warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars()); | |
529 } | |
530 | |
531 if (fdv.toParent() == parent) | |
532 { | |
533 // If both are mixins, then error. | |
534 // If either is not, the one that is not overrides | |
535 // the other. | |
536 if (fdv.parent.isClassDeclaration()) | |
537 break; | |
538 if (!this.parent.isClassDeclaration() | |
539 ///static if (!BREAKABI) { | |
540 && !isDtorDeclaration() | |
541 ///} | |
542 ///version (DMDV2) { | |
543 && !isPostBlitDeclaration() | |
544 ///} | |
545 ) | |
546 error("multiple overrides of same function"); | |
547 } | |
548 cd.vtbl.data[vi] = cast(void*)this; | |
549 vtblIndex = vi; | |
550 | |
551 /* This works by whenever this function is called, | |
552 * it actually returns tintro, which gets dynamically | |
553 * cast to type. But we know that tintro is a base | |
554 * of type, so we could optimize it by not doing a | |
555 * dynamic cast, but just subtracting the isBaseOf() | |
556 * offset if the value is != null. | |
557 */ | |
558 | |
559 if (fdv.tintro) | |
560 tintro = fdv.tintro; | |
561 else if (!type.equals(fdv.type)) | |
562 { | |
563 /* Only need to have a tintro if the vptr | |
564 * offsets differ | |
565 */ | |
566 int offset; | |
567 if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset)) | |
568 { | |
569 tintro = fdv.type; | |
570 } | |
571 } | |
572 break; | |
573 } | |
574 } | |
575 | |
576 /* Go through all the interface bases. | |
577 * If this function is covariant with any members of those interface | |
578 * functions, set the tintro. | |
579 */ | |
580 for (int i = 0; i < cd.interfaces_dim; i++) | |
581 { | |
582 BaseClass b = cd.interfaces[i]; | |
583 vi = findVtblIndex(b.base.vtbl, b.base.vtbl.dim); | |
584 switch (vi) | |
585 { | |
586 case -1: | |
587 break; | |
588 | |
589 case -2: | |
590 cd.sizeok = 2; // can't finish due to forward reference | |
591 return; | |
592 | |
593 default: | |
594 { FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi]; | |
595 Type ti = null; | |
596 | |
597 if (fdv.tintro) | |
598 ti = fdv.tintro; | |
599 else if (!type.equals(fdv.type)) | |
600 { | |
601 /* Only need to have a tintro if the vptr | |
602 * offsets differ | |
603 */ | |
604 int offset; | |
605 if (fdv.type.nextOf().isBaseOf(type.nextOf(), &offset)) | |
606 { | |
607 ti = fdv.type; | |
608 static if (false) { | |
609 if (offset) | |
610 ti = fdv.type; | |
611 else if (type.nextOf().ty == Tclass) | |
612 { | |
613 ClassDeclaration cdn = (cast(TypeClass)type.nextOf()).sym; | |
614 if (cdn && cdn.sizeok != 1) | |
615 ti = fdv.type; | |
616 } | |
617 } | |
618 } | |
619 } | |
620 if (ti) | |
621 { | |
622 if (tintro && !tintro.equals(ti)) | |
623 { | |
624 error("incompatible covariant types %s and %s", tintro.toChars(), ti.toChars()); | |
625 } | |
626 tintro = ti; | |
627 } | |
628 goto L2; | |
629 } | |
630 } | |
631 } | |
632 | |
633 if (introducing && isOverride()) | |
634 { | |
635 error("does not override any function"); | |
636 } | |
637 | |
638 L2: ; | |
639 } | |
640 else if (isOverride() && !parent.isTemplateInstance()) | |
641 error("override only applies to class member functions"); | |
642 | |
643 /* Do not allow template instances to add virtual functions | |
644 * to a class. | |
645 */ | |
646 if (isVirtual()) | |
647 { | |
648 TemplateInstance ti = parent.isTemplateInstance(); | |
649 if (ti) | |
650 { | |
651 // Take care of nested templates | |
652 while (1) | |
653 { | |
654 TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); | |
655 if (!ti2) | |
656 break; | |
657 ti = ti2; | |
658 } | |
659 | |
660 // If it's a member template | |
661 ClassDeclaration cdd = ti.tempdecl.isClassMember(); | |
662 if (cdd) | |
663 { | |
664 error("cannot use template to add virtual function to class '%s'", cdd.toChars()); | |
665 } | |
666 } | |
667 } | |
668 | |
669 if (isMain()) | |
670 { | |
671 // Check parameters to see if they are either () or (char[][] args) | |
672 switch (nparams) | |
673 { | |
674 case 0: | |
675 break; | |
676 | |
677 case 1: | |
678 { | |
679 Argument arg0 = Argument.getNth(f.parameters, 0); | |
680 if (arg0.type.ty != TY.Tarray || | |
681 arg0.type.nextOf().ty != TY.Tarray || | |
682 arg0.type.nextOf().nextOf().ty != TY.Tchar || | |
683 arg0.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) | |
684 goto Lmainerr; | |
685 break; | |
686 } | |
687 | |
688 default: | |
689 goto Lmainerr; | |
690 } | |
691 | |
692 if (f.nextOf().ty != TY.Tint32 && f.nextOf().ty != TY.Tvoid) | |
693 error("must return int or void, not %s", f.nextOf().toChars()); | |
694 if (f.varargs) | |
695 { | |
696 Lmainerr: | |
697 error("parameters must be main() or main(char[][] args)"); | |
698 } | |
699 } | |
700 | |
701 if (ident == Id.assign && (sd || cd)) | |
702 { // Disallow identity assignment operator. | |
703 | |
704 // opAssign(...) | |
705 if (nparams == 0) | |
706 { if (f.varargs == 1) | |
707 goto Lassignerr; | |
708 } | |
709 else | |
710 { | |
711 Argument arg0 = Argument.getNth(f.parameters, 0); | |
712 Type t0 = arg0.type.toBasetype(); | |
713 Type tb = sd ? sd.type : cd.type; | |
714 if (arg0.type.implicitConvTo(tb) || | |
715 (sd && t0.ty == TY.Tpointer && t0.nextOf().implicitConvTo(tb)) | |
716 ) | |
717 { | |
718 if (nparams == 1) | |
719 goto Lassignerr; | |
720 Argument arg1 = Argument.getNth(f.parameters, 1); | |
721 if (arg1.defaultArg) | |
722 goto Lassignerr; | |
723 } | |
724 } | |
725 } | |
726 | |
727 Ldone: | |
728 /* Save scope for possible later use (if we need the | |
729 * function internals) | |
730 */ | |
731 scope_ = new Scope(sc); | |
732 scope_.setNoFree(); | |
733 return; | |
734 | |
735 Lassignerr: | |
736 if (sd) | |
737 { | |
738 sd.hasIdentityAssign = 1; // don't need to generate it | |
739 goto Ldone; | |
740 } | |
741 error("identity assignment operator overload is illegal"); | |
742 } | |
743 | |
744 void semantic2(Scope sc) | |
745 { | |
746 } | |
747 | |
748 // Do the semantic analysis on the internals of the function. | |
749 void semantic3(Scope sc) | |
750 { | |
751 TypeFunction f; | |
752 VarDeclaration argptr = null; | |
753 VarDeclaration _arguments = null; | |
754 | |
755 if (!parent) | |
756 { | |
757 if (global.errors) | |
758 return; | |
759 //printf("FuncDeclaration.semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); | |
760 assert(0); | |
761 } | |
762 //printf("FuncDeclaration.semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars()); | |
763 //fflush(stdout); | |
764 //printf("storage class = x%x %x\n", sc.stc, storage_class); | |
765 //{ static int x; if (++x == 2) *(char*)0=0; } | |
766 //printf("\tlinkage = %d\n", sc.linkage); | |
767 | |
768 //printf(" sc.incontract = %d\n", sc.incontract); | |
769 if (semanticRun >= 3) | |
770 return; | |
771 semanticRun = 3; | |
772 | |
773 if (!type || type.ty != TY.Tfunction) | |
774 return; | |
775 f = cast(TypeFunction)(type); | |
776 | |
777 // Check the 'throws' clause | |
778 if (fthrows) | |
779 { | |
780 for (int i = 0; i < fthrows.dim; i++) | |
781 { | |
782 Type t = cast(Type)fthrows.data[i]; | |
783 | |
784 t = t.semantic(loc, sc); | |
785 if (!t.isClassHandle()) | |
786 error("can only throw classes, not %s", t.toChars()); | |
787 } | |
788 } | |
789 | |
790 if (fbody || frequire) | |
791 { | |
792 /* Symbol table into which we place parameters and nested functions, | |
793 * solely to diagnose name collisions. | |
794 */ | |
795 localsymtab = new DsymbolTable(); | |
796 | |
797 // Establish function scope | |
798 ScopeDsymbol ss = new ScopeDsymbol(); | |
799 ss.parent = sc.scopesym; | |
800 Scope sc2 = sc.push(ss); | |
801 sc2.func = this; | |
802 sc2.parent = this; | |
803 sc2.callSuper = 0; | |
804 sc2.sbreak = null; | |
805 sc2.scontinue = null; | |
806 sc2.sw = null; | |
807 sc2.fes = fes; | |
808 sc2.linkage = LINK.LINKd; | |
809 sc2.stc &= ~(STC.STCauto | STC.STCscope | STC.STCstatic | STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCfinal | STC.STCtls | STC.STCgshared | STC.STCref); | |
810 sc2.protection = PROT.PROTpublic; | |
811 sc2.explicitProtection = 0; | |
812 sc2.structalign = 8; | |
813 sc2.incontract = 0; | |
814 sc2.tf = null; | |
815 sc2.noctor = 0; | |
816 | |
817 // Declare 'this' | |
818 AggregateDeclaration ad = isThis(); | |
819 if (ad) | |
820 { VarDeclaration v; | |
821 | |
822 if (isFuncLiteralDeclaration() && isNested()) | |
823 { | |
824 error("literals cannot be class members"); | |
825 return; | |
826 } | |
827 else | |
828 { | |
829 assert(!isNested()); // can't be both member and nested | |
830 assert(ad.handle); | |
831 Type thandle = ad.handle; | |
832 version (STRUCTTHISREF) { | |
833 thandle = thandle.addMod(type.mod); | |
834 thandle = thandle.addStorageClass(storage_class); | |
835 if (isPure()) | |
836 thandle = thandle.addMod(MOD.MODconst); | |
837 } else { | |
838 if (storage_class & STC.STCconst || type.isConst()) | |
839 { | |
840 assert(0); // BUG: shared not handled | |
841 if (thandle.ty == TY.Tclass) | |
842 thandle = thandle.constOf(); | |
843 else | |
844 { assert(thandle.ty == TY.Tpointer); | |
845 thandle = thandle.nextOf().constOf().pointerTo(); | |
846 } | |
847 } | |
848 else if (storage_class & STC.STCimmutable || type.isInvariant()) | |
849 { | |
850 if (thandle.ty == TY.Tclass) | |
851 thandle = thandle.invariantOf(); | |
852 else | |
853 { assert(thandle.ty == TY.Tpointer); | |
854 thandle = thandle.nextOf().invariantOf().pointerTo(); | |
855 } | |
856 } | |
857 else if (storage_class & STC.STCshared || type.isShared()) | |
858 { | |
859 assert(0); // not implemented | |
860 } | |
861 } | |
862 v = new ThisDeclaration(loc, thandle); | |
863 v.storage_class |= STC.STCparameter; | |
864 version (STRUCTTHISREF) { | |
865 if (thandle.ty == TY.Tstruct) | |
866 v.storage_class |= STC.STCref; | |
867 } | |
868 v.semantic(sc2); | |
869 if (!sc2.insert(v)) | |
870 assert(0); | |
871 v.parent = this; | |
872 vthis = v; | |
873 } | |
874 } | |
875 else if (isNested()) | |
876 { | |
877 /* The 'this' for a nested function is the link to the | |
878 * enclosing function's stack frame. | |
879 * Note that nested functions and member functions are disjoint. | |
880 */ | |
881 VarDeclaration v = new ThisDeclaration(loc, Type.tvoid.pointerTo()); | |
882 v.storage_class |= STC.STCparameter; | |
883 v.semantic(sc2); | |
884 if (!sc2.insert(v)) | |
885 assert(0); | |
886 v.parent = this; | |
887 vthis = v; | |
888 } | |
889 | |
890 // Declare hidden variable _arguments[] and _argptr | |
891 if (f.varargs == 1) | |
892 { | |
893 version (TARGET_NET) { | |
894 varArgs(sc2, f, argptr, _arguments); | |
895 } else { | |
896 Type t; | |
897 | |
898 if (f.linkage == LINK.LINKd) | |
899 { | |
900 // Declare _arguments[] | |
901 version (BREAKABI) { | |
902 v_arguments = new VarDeclaration(Loc(0), Type.typeinfotypelist.type, Id._arguments_typeinfo, null); | |
903 v_arguments.storage_class = STCparameter; | |
904 v_arguments.semantic(sc2); | |
905 sc2.insert(v_arguments); | |
906 v_arguments.parent = this; | |
907 | |
908 //t = Type.typeinfo.type.constOf().arrayOf(); | |
909 t = Type.typeinfo.type.arrayOf(); | |
910 _arguments = new VarDeclaration(Loc(0), t, Id._arguments, null); | |
911 _arguments.semantic(sc2); | |
912 sc2.insert(_arguments); | |
913 _arguments.parent = this; | |
914 } else { | |
915 t = Type.typeinfo.type.arrayOf(); | |
916 v_arguments = new VarDeclaration(Loc(0), t, Id._arguments, null); | |
917 v_arguments.storage_class = STC.STCparameter | STC.STCin; | |
918 v_arguments.semantic(sc2); | |
919 sc2.insert(v_arguments); | |
920 v_arguments.parent = this; | |
921 } | |
922 } | |
923 if (f.linkage == LINK.LINKd || (parameters && parameters.dim)) | |
924 { // Declare _argptr | |
925 version (IN_GCC) { | |
926 t = d_gcc_builtin_va_list_d_type; | |
927 } else { | |
928 t = Type.tvoid.pointerTo(); | |
929 } | |
930 argptr = new VarDeclaration(Loc(0), t, Id._argptr, null); | |
931 argptr.semantic(sc2); | |
932 sc2.insert(argptr); | |
933 argptr.parent = this; | |
934 } | |
935 } | |
936 } | |
937 | |
938 // Propagate storage class from tuple parameters to their element-parameters. | |
939 if (f.parameters) | |
940 { | |
941 for (size_t i = 0; i < f.parameters.dim; i++) | |
942 { Argument arg = cast(Argument)f.parameters.data[i]; | |
943 | |
944 //printf("[%d] arg.type.ty = %d %s\n", i, arg.type.ty, arg.type.toChars()); | |
945 if (arg.type.ty == TY.Ttuple) | |
946 { TypeTuple t = cast(TypeTuple)arg.type; | |
947 size_t dim = Argument.dim(t.arguments); | |
948 for (size_t j = 0; j < dim; j++) | |
949 { Argument narg = Argument.getNth(t.arguments, j); | |
950 narg.storageClass = arg.storageClass; | |
951 } | |
952 } | |
953 } | |
954 } | |
955 | |
956 /* Declare all the function parameters as variables | |
957 * and install them in parameters[] | |
958 */ | |
959 size_t nparams = Argument.dim(f.parameters); | |
960 if (nparams) | |
961 { /* parameters[] has all the tuples removed, as the back end | |
962 * doesn't know about tuples | |
963 */ | |
964 parameters = new Dsymbols(); | |
965 parameters.reserve(nparams); | |
966 for (size_t i = 0; i < nparams; i++) | |
967 { | |
968 Argument arg = Argument.getNth(f.parameters, i); | |
969 Identifier id = arg.ident; | |
970 if (!id) | |
971 { | |
972 /* Generate identifier for un-named parameter, | |
973 * because we need it later on. | |
974 */ | |
975 arg.ident = id = Identifier.generateId("_param_", i); | |
976 } | |
977 Type vtype = arg.type; | |
978 if (isPure()) | |
979 vtype = vtype.addMod(MOD.MODconst); | |
980 VarDeclaration v = new VarDeclaration(loc, vtype, id, null); | |
981 //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars()); | |
982 v.storage_class |= STC.STCparameter; | |
983 if (f.varargs == 2 && i + 1 == nparams) | |
984 v.storage_class |= STC.STCvariadic; | |
985 v.storage_class |= arg.storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STClazy | STC.STCfinal | STC.STC_TYPECTOR | STC.STCnodtor); | |
986 v.semantic(sc2); | |
987 if (!sc2.insert(v)) | |
988 error("parameter %s.%s is already defined", toChars(), v.toChars()); | |
989 else | |
990 parameters.push(cast(void*)v); | |
991 localsymtab.insert(v); | |
992 v.parent = this; | |
993 } | |
994 } | |
995 | |
996 // Declare the tuple symbols and put them in the symbol table, | |
997 // but not in parameters[]. | |
998 if (f.parameters) | |
999 { | |
1000 for (size_t i = 0; i < f.parameters.dim; i++) | |
1001 { Argument arg = cast(Argument)f.parameters.data[i]; | |
1002 | |
1003 if (!arg.ident) | |
1004 continue; // never used, so ignore | |
1005 if (arg.type.ty == TY.Ttuple) | |
1006 { TypeTuple t = cast(TypeTuple)arg.type; | |
1007 size_t dim = Argument.dim(t.arguments); | |
1008 Objects exps = new Objects(); | |
1009 exps.setDim(dim); | |
1010 for (size_t j = 0; j < dim; j++) | |
1011 { Argument narg = Argument.getNth(t.arguments, j); | |
1012 assert(narg.ident); | |
1013 VarDeclaration v = sc2.search(Loc(0), narg.ident, null).isVarDeclaration(); | |
1014 assert(v); | |
1015 Expression e = new VarExp(v.loc, v); | |
1016 exps.data[j] = cast(void*)e; | |
1017 } | |
1018 assert(arg.ident); | |
1019 TupleDeclaration v = new TupleDeclaration(loc, arg.ident, exps); | |
1020 //printf("declaring tuple %s\n", v.toChars()); | |
1021 v.isexp = 1; | |
1022 if (!sc2.insert(v)) | |
1023 error("parameter %s.%s is already defined", toChars(), v.toChars()); | |
1024 localsymtab.insert(v); | |
1025 v.parent = this; | |
1026 } | |
1027 } | |
1028 } | |
1029 | |
1030 /* Do the semantic analysis on the [in] preconditions and | |
1031 * [out] postconditions. | |
1032 */ | |
1033 sc2.incontract++; | |
1034 | |
1035 if (frequire) | |
1036 { /* frequire is composed of the [in] contracts | |
1037 */ | |
1038 // BUG: need to error if accessing out parameters | |
1039 // BUG: need to treat parameters as const | |
1040 // BUG: need to disallow returns and throws | |
1041 // BUG: verify that all in and ref parameters are read | |
1042 frequire = frequire.semantic(sc2); | |
1043 labtab = null; // so body can't refer to labels | |
1044 } | |
1045 | |
1046 if (fensure || addPostInvariant()) | |
1047 { /* fensure is composed of the [out] contracts | |
1048 */ | |
1049 ScopeDsymbol sym = new ScopeDsymbol(); | |
1050 sym.parent = sc2.scopesym; | |
1051 sc2 = sc2.push(sym); | |
1052 | |
1053 assert(type.nextOf()); | |
1054 if (type.nextOf().ty == TY.Tvoid) | |
1055 { | |
1056 if (outId) | |
1057 error("void functions have no result"); | |
1058 } | |
1059 else | |
1060 { | |
1061 if (!outId) | |
1062 outId = Id.result; // provide a default | |
1063 } | |
1064 | |
1065 if (outId) | |
1066 { // Declare result variable | |
1067 VarDeclaration v; | |
1068 Loc loc = this.loc; | |
1069 | |
1070 if (fensure) | |
1071 loc = fensure.loc; | |
1072 | |
1073 v = new VarDeclaration(loc, type.nextOf(), outId, null); | |
1074 v.noauto = true; | |
1075 version (DMDV2) { | |
1076 if (f.isref) | |
1077 { | |
1078 v.storage_class |= STC.STCref | STC.STCforeach; | |
1079 } | |
1080 } | |
1081 sc2.incontract--; | |
1082 v.semantic(sc2); | |
1083 sc2.incontract++; | |
1084 if (!sc2.insert(v)) | |
1085 error("out result %s is already defined", v.toChars()); | |
1086 v.parent = this; | |
1087 vresult = v; | |
1088 | |
1089 // vresult gets initialized with the function return value | |
1090 // in ReturnStatement.semantic() | |
1091 } | |
1092 | |
1093 // BUG: need to treat parameters as const | |
1094 // BUG: need to disallow returns and throws | |
1095 if (fensure) | |
1096 { fensure = fensure.semantic(sc2); | |
1097 labtab = null; // so body can't refer to labels | |
1098 } | |
1099 | |
1100 if (!global.params.useOut) | |
1101 { fensure = null; // discard | |
1102 vresult = null; | |
1103 } | |
1104 | |
1105 // Postcondition invariant | |
1106 if (addPostInvariant()) | |
1107 { | |
1108 Expression e = null; | |
1109 if (isCtorDeclaration()) | |
1110 { | |
1111 // Call invariant directly only if it exists | |
1112 InvariantDeclaration inv = ad.inv; | |
1113 ClassDeclaration cd = ad.isClassDeclaration(); | |
1114 | |
1115 while (!inv && cd) | |
1116 { | |
1117 cd = cd.baseClass; | |
1118 if (!cd) | |
1119 break; | |
1120 inv = cd.inv; | |
1121 } | |
1122 if (inv) | |
1123 { | |
1124 e = new DsymbolExp(Loc(0), inv); | |
1125 e = new CallExp(Loc(0), e); | |
1126 e = e.semantic(sc2); | |
1127 } | |
1128 } | |
1129 else | |
1130 { // Call invariant virtually | |
1131 Expression v = new ThisExp(Loc(0)); | |
1132 v.type = vthis.type; | |
1133 version (STRUCTTHISREF) { | |
1134 if (ad.isStructDeclaration()) | |
1135 v = v.addressOf(sc); | |
1136 } | |
1137 e = new AssertExp(Loc(0), v); | |
1138 } | |
1139 if (e) | |
1140 { | |
1141 ExpStatement s = new ExpStatement(Loc(0), e); | |
1142 if (fensure) | |
1143 fensure = new CompoundStatement(Loc(0), s, fensure); | |
1144 else | |
1145 fensure = s; | |
1146 } | |
1147 } | |
1148 | |
1149 if (fensure) | |
1150 { returnLabel = new LabelDsymbol(Id.returnLabel); | |
1151 LabelStatement ls = new LabelStatement(Loc(0), Id.returnLabel, fensure); | |
1152 ls.isReturnLabel = 1; | |
1153 returnLabel.statement = ls; | |
1154 } | |
1155 sc2 = sc2.pop(); | |
1156 } | |
1157 | |
1158 sc2.incontract--; | |
1159 | |
1160 if (fbody) | |
1161 { ClassDeclaration cd = isClassMember(); | |
1162 | |
1163 /* If this is a class constructor | |
1164 */ | |
1165 if (isCtorDeclaration() && cd) | |
1166 { | |
1167 for (int i = 0; i < cd.fields.dim; i++) | |
1168 { VarDeclaration v = cast(VarDeclaration)cd.fields.data[i]; | |
1169 | |
1170 v.ctorinit = 0; | |
1171 } | |
1172 } | |
1173 | |
1174 if (inferRetType || f.retStyle() != RET.RETstack) | |
1175 nrvo_can = 0; | |
1176 | |
1177 fbody = fbody.semantic(sc2); | |
1178 if (!fbody) | |
1179 fbody = new CompoundStatement(Loc(0), new Statements()); | |
1180 | |
1181 if (inferRetType) | |
1182 { // If no return type inferred yet, then infer a void | |
1183 if (!type.nextOf()) | |
1184 { | |
1185 (cast(TypeFunction)type).next = Type.tvoid; | |
1186 type = type.semantic(loc, sc); | |
1187 } | |
1188 f = cast(TypeFunction)type; | |
1189 } | |
1190 | |
1191 if (isStaticCtorDeclaration()) | |
1192 { | |
1193 /* It's a static constructor. Ensure that all | |
1194 * ctor consts were initialized. | |
1195 */ | |
1196 | |
1197 Dsymbol p = toParent(); | |
1198 ScopeDsymbol add = p.isScopeDsymbol(); | |
1199 if (!add) | |
1200 { | |
1201 error("static constructor can only be member of struct/class/module, not %s %s", p.kind(), p.toChars()); | |
1202 } | |
1203 else | |
1204 { | |
1205 for (int i = 0; i < add.members.dim; i++) | |
1206 { Dsymbol s = cast(Dsymbol)add.members.data[i]; | |
1207 | |
1208 s.checkCtorConstInit(); | |
1209 } | |
1210 } | |
1211 } | |
1212 | |
1213 if (isCtorDeclaration() && cd) | |
1214 { | |
1215 //printf("callSuper = x%x\n", sc2.callSuper); | |
1216 | |
1217 // Verify that all the ctorinit fields got initialized | |
1218 if (!(sc2.callSuper & CSX.CSXthis_ctor)) | |
1219 { | |
1220 for (int i = 0; i < cd.fields.dim; i++) | |
1221 { VarDeclaration v = cast(VarDeclaration)cd.fields.data[i]; | |
1222 | |
1223 if (v.ctorinit == 0 && v.isCtorinit()) | |
1224 error("missing initializer for final field %s", v.toChars()); | |
1225 } | |
1226 } | |
1227 | |
1228 if (!(sc2.callSuper & CSX.CSXany_ctor) && | |
1229 cd.baseClass && cd.baseClass.ctor) | |
1230 { | |
1231 sc2.callSuper = 0; | |
1232 | |
1233 // Insert implicit super() at start of fbody | |
1234 Expression e1 = new SuperExp(Loc(0)); | |
1235 Expression e = new CallExp(Loc(0), e1); | |
1236 | |
1237 e = e.trySemantic(sc2); | |
1238 if (!e) | |
1239 error("no match for implicit super() call in constructor"); | |
1240 else | |
1241 { | |
1242 Statement s = new ExpStatement(Loc(0), e); | |
1243 fbody = new CompoundStatement(Loc(0), s, fbody); | |
1244 } | |
1245 } | |
1246 } | |
1247 else if (fes) | |
1248 { // For foreach(){} body, append a return 0; | |
1249 Expression e = new IntegerExp(0); | |
1250 Statement s = new ReturnStatement(Loc(0), e); | |
1251 fbody = new CompoundStatement(Loc(0), fbody, s); | |
1252 assert(!returnLabel); | |
1253 } | |
1254 else if (!hasReturnExp && type.nextOf().ty != TY.Tvoid) | |
1255 error("expected to return a value of type %s", type.nextOf().toChars()); | |
1256 else if (!inlineAsm) | |
1257 { | |
1258 version (DMDV2) { | |
1259 BE blockexit = fbody ? fbody.blockExit() : BE.BEfallthru; | |
1260 if (f.isnothrow && blockexit & BE.BEthrow) | |
1261 error("'%s' is nothrow yet may throw", toChars()); | |
1262 | |
1263 int offend = blockexit & BE.BEfallthru; | |
1264 } | |
1265 if (type.nextOf().ty == TY.Tvoid) | |
1266 { | |
1267 if (offend && isMain()) | |
1268 { // Add a return 0; statement | |
1269 Statement s = new ReturnStatement(Loc(0), new IntegerExp(0)); | |
1270 fbody = new CompoundStatement(Loc(0), fbody, s); | |
1271 } | |
1272 } | |
1273 else | |
1274 { | |
1275 if (offend) | |
1276 { | |
1277 Expression e; | |
1278 version (DMDV1) { | |
1279 warning(loc, "no return exp; or assert(0); at end of function"); | |
1280 } else { | |
1281 error("no return exp; or assert(0); at end of function"); | |
1282 } | |
1283 if (global.params.useAssert && | |
1284 !global.params.useInline) | |
1285 { /* Add an assert(0, msg); where the missing return | |
1286 * should be. | |
1287 */ | |
1288 e = new AssertExp( | |
1289 endloc, | |
1290 new IntegerExp(0), | |
1291 new StringExp(loc, "missing return expression") | |
1292 ); | |
1293 } | |
1294 else | |
1295 e = new HaltExp(endloc); | |
1296 | |
1297 e = new CommaExp(Loc(0), e, type.nextOf().defaultInit(Loc(0))); | |
1298 e = e.semantic(sc2); | |
1299 Statement s = new ExpStatement(Loc(0), e); | |
1300 fbody = new CompoundStatement(Loc(0), fbody, s); | |
1301 } | |
1302 } | |
1303 } | |
1304 } | |
1305 | |
1306 { | |
1307 Statements a = new Statements(); | |
1308 | |
1309 // Merge in initialization of 'out' parameters | |
1310 if (parameters) | |
1311 { for (size_t i = 0; i < parameters.dim; i++) | |
1312 { | |
1313 VarDeclaration v = cast(VarDeclaration)parameters.data[i]; | |
1314 if (v.storage_class & STC.STCout) | |
1315 { | |
1316 assert(v.init); | |
1317 ExpInitializer ie = v.init.isExpInitializer(); | |
1318 assert(ie); | |
1319 a.push(cast(void*)new ExpStatement(Loc(0), ie.exp)); | |
1320 } | |
1321 } | |
1322 } | |
1323 | |
1324 if (argptr) | |
1325 { // Initialize _argptr to point past non-variadic arg | |
1326 version (IN_GCC) { | |
1327 // Handled in FuncDeclaration.toObjFile | |
1328 v_argptr = argptr; | |
1329 v_argptr.init = new VoidInitializer(loc); | |
1330 } else { | |
1331 Expression e1; | |
1332 Expression e; | |
1333 Type t = argptr.type; | |
1334 VarDeclaration p; | |
1335 uint offset; | |
1336 | |
1337 e1 = new VarExp(Loc(0), argptr); | |
1338 if (parameters && parameters.dim) | |
1339 p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; | |
1340 else | |
1341 p = v_arguments; // last parameter is _arguments[] | |
1342 offset = cast(uint)p.type.size(); /// | |
1343 offset = (offset + 3) & ~3; // assume stack aligns on 4 | |
1344 e = new SymOffExp(Loc(0), p, offset); | |
1345 e = new AssignExp(Loc(0), e1, e); | |
1346 e.type = t; | |
1347 a.push(cast(void*)new ExpStatement(Loc(0), e)); | |
1348 } | |
1349 } | |
1350 | |
1351 if (_arguments) | |
1352 { | |
1353 /* Advance to elements[] member of TypeInfo_Tuple with: | |
1354 * _arguments = v_arguments.elements; | |
1355 */ | |
1356 Expression e = new VarExp(Loc(0), v_arguments); | |
1357 e = new DotIdExp(Loc(0), e, Id.elements); | |
1358 Expression e1 = new VarExp(Loc(0), _arguments); | |
1359 e = new AssignExp(Loc(0), e1, e); | |
1360 e.op = TOK.TOKconstruct; | |
1361 e = e.semantic(sc2); | |
1362 a.push(cast(void*)new ExpStatement(Loc(0), e)); | |
1363 } | |
1364 | |
1365 // Merge contracts together with body into one compound statement | |
1366 | |
1367 version (_DH) { | |
1368 if (frequire && global.params.useIn) | |
1369 { frequire.incontract = 1; | |
1370 a.push(frequire); | |
1371 } | |
1372 } else { | |
1373 if (frequire && global.params.useIn) | |
1374 a.push(cast(void*)frequire); | |
1375 } | |
1376 | |
1377 // Precondition invariant | |
1378 if (addPreInvariant()) | |
1379 { | |
1380 Expression e = null; | |
1381 if (isDtorDeclaration()) | |
1382 { | |
1383 // Call invariant directly only if it exists | |
1384 InvariantDeclaration inv = ad.inv; | |
1385 ClassDeclaration cd = ad.isClassDeclaration(); | |
1386 | |
1387 while (!inv && cd) | |
1388 { | |
1389 cd = cd.baseClass; | |
1390 if (!cd) | |
1391 break; | |
1392 inv = cd.inv; | |
1393 } | |
1394 if (inv) | |
1395 { | |
1396 e = new DsymbolExp(Loc(0), inv); | |
1397 e = new CallExp(Loc(0), e); | |
1398 e = e.semantic(sc2); | |
1399 } | |
1400 } | |
1401 else | |
1402 { // Call invariant virtually | |
1403 Expression v = new ThisExp(Loc(0)); | |
1404 v.type = vthis.type; | |
1405 version (STRUCTTHISREF) { | |
1406 if (ad.isStructDeclaration()) | |
1407 v = v.addressOf(sc); | |
1408 } | |
1409 Expression se = new StringExp(Loc(0), "null this"); | |
1410 se = se.semantic(sc); | |
1411 se.type = Type.tchar.arrayOf(); | |
1412 e = new AssertExp(loc, v, se); | |
1413 } | |
1414 if (e) | |
1415 { | |
1416 ExpStatement s = new ExpStatement(Loc(0), e); | |
1417 a.push(cast(void*)s); | |
1418 } | |
1419 } | |
1420 | |
1421 if (fbody) | |
1422 a.push(cast(void*)fbody); | |
1423 | |
1424 if (fensure) | |
1425 { | |
1426 a.push(cast(void*)returnLabel.statement); | |
1427 | |
1428 if (type.nextOf().ty != TY.Tvoid) | |
1429 { | |
1430 // Create: return vresult; | |
1431 assert(vresult); | |
1432 Expression e = new VarExp(Loc(0), vresult); | |
1433 if (tintro) | |
1434 { e = e.implicitCastTo(sc, tintro.nextOf()); | |
1435 e = e.semantic(sc); | |
1436 } | |
1437 ReturnStatement s = new ReturnStatement(Loc(0), e); | |
1438 a.push(cast(void*)s); | |
1439 } | |
1440 } | |
1441 | |
1442 fbody = new CompoundStatement(Loc(0), a); | |
1443 version (DMDV2) { | |
1444 /* Append destructor calls for parameters as finally blocks. | |
1445 */ | |
1446 if (parameters) | |
1447 { for (size_t i = 0; i < parameters.dim; i++) | |
1448 { | |
1449 VarDeclaration v = cast(VarDeclaration)parameters.data[i]; | |
1450 | |
1451 if (v.storage_class & (STC.STCref | STC.STCout)) | |
1452 continue; | |
1453 | |
1454 /* Don't do this for static arrays, since static | |
1455 * arrays are called by reference. Remove this | |
1456 * when we change them to call by value. | |
1457 */ | |
1458 if (v.type.toBasetype().ty == TY.Tsarray) | |
1459 continue; | |
1460 | |
1461 Expression e = v.callAutoDtor(sc); | |
1462 if (e) | |
1463 { Statement s = new ExpStatement(Loc(0), e); | |
1464 s = s.semantic(sc); | |
1465 if (fbody.blockExit() == BE.BEfallthru) | |
1466 fbody = new CompoundStatement(Loc(0), fbody, s); | |
1467 else | |
1468 fbody = new TryFinallyStatement(Loc(0), fbody, s); | |
1469 } | |
1470 } | |
1471 } | |
1472 } | |
1473 | |
1474 static if (true) { | |
1475 if (isSynchronized()) | |
1476 { /* Wrap the entire function body in a synchronized statement | |
1477 */ | |
1478 ClassDeclaration cd = parent.isClassDeclaration(); | |
1479 if (cd) | |
1480 { | |
1481 ///version (TARGET_WINDOS) { | |
1482 if (/*config.flags2 & CFG2.CFG2seh &&*/ // always on for WINDOS | |
1483 !isStatic() && !fbody.usesEH()) | |
1484 { | |
1485 /* The back end uses the "jmonitor" hack for syncing; | |
1486 * no need to do the sync at this level. | |
1487 */ | |
1488 } | |
1489 else | |
1490 ///} | |
1491 { | |
1492 Expression vsync; | |
1493 if (isStatic()) | |
1494 { | |
1495 // The monitor is in the ClassInfo | |
1496 vsync = new DotIdExp(loc, new DsymbolExp(loc, cd), Id.classinfo_); | |
1497 } | |
1498 else | |
1499 { // 'this' is the monitor | |
1500 vsync = new VarExp(loc, vthis); | |
1501 } | |
1502 fbody = new PeelStatement(fbody); // don't redo semantic() | |
1503 fbody = new SynchronizedStatement(loc, vsync, fbody); | |
1504 fbody = fbody.semantic(sc2); | |
1505 } | |
1506 } | |
1507 else | |
1508 { | |
1509 error("synchronized function %s must be a member of a class", toChars()); | |
1510 } | |
1511 } | |
1512 } | |
1513 } | |
1514 | |
1515 sc2.callSuper = 0; | |
1516 sc2.pop(); | |
1517 } | |
1518 semanticRun = 4; | |
1519 } | |
1520 | |
1521 // called from semantic3 | |
1522 void varArgs(Scope sc, TypeFunction, ref VarDeclaration, ref VarDeclaration) | |
1523 { | |
1524 assert(false); | |
1525 } | |
1526 | |
1527 void toCBuffer(OutBuffer buf, HdrGenState* hgs) | |
1528 { | |
1529 assert(false); | |
1530 } | |
1531 | |
1532 void bodyToCBuffer(OutBuffer buf, HdrGenState* hgs) | |
1533 { | |
1534 assert(false); | |
1535 } | |
1536 | |
1537 /**************************************************** | |
1538 * Determine if 'this' overrides fd. | |
1539 * Return true if it does. | |
1540 */ | |
1541 bool overrides(FuncDeclaration fd) | |
1542 { | |
1543 bool result = false; | |
1544 | |
1545 if (fd.ident == ident) | |
1546 { | |
1547 int cov = type.covariant(fd.type); | |
1548 if (cov) | |
1549 { | |
1550 ClassDeclaration cd1 = toParent().isClassDeclaration(); | |
1551 ClassDeclaration cd2 = fd.toParent().isClassDeclaration(); | |
1552 | |
1553 if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) | |
1554 result = true; | |
1555 } | |
1556 } | |
1557 return result; | |
1558 } | |
1559 | |
1560 /************************************************* | |
1561 * Find index of function in vtbl[0..dim] that | |
1562 * this function overrides. | |
1563 * Returns: | |
1564 * -1 didn't find one | |
1565 * -2 can't determine because of forward references | |
1566 */ | |
1567 int findVtblIndex(Array vtbl, int dim) | |
1568 { | |
1569 for (int vi = 0; vi < dim; vi++) | |
1570 { | |
1571 FuncDeclaration fdv = (cast(Dsymbol)vtbl.data[vi]).isFuncDeclaration(); | |
1572 if (fdv && fdv.ident is ident) | |
1573 { | |
1574 int cov = type.covariant(fdv.type); | |
1575 //printf("\tbaseclass cov = %d\n", cov); | |
1576 switch (cov) | |
1577 { | |
1578 case 0: // types are distinct | |
1579 break; | |
1580 | |
1581 case 1: | |
1582 return vi; | |
1583 | |
1584 case 2: | |
1585 //type.print(); | |
1586 //fdv.type.print(); | |
1587 //printf("%s %s\n", type.deco, fdv.type.deco); | |
1588 error("of type %s overrides but is not covariant with %s of type %s", | |
1589 type.toChars(), fdv.toPrettyChars(), fdv.type.toChars()); | |
1590 break; | |
1591 | |
1592 case 3: | |
1593 return -2; // forward references | |
1594 } | |
1595 } | |
1596 } | |
1597 return -1; | |
1598 } | |
1599 | |
1600 /**************************************************** | |
1601 * Overload this FuncDeclaration with the new one f. | |
1602 * Return !=0 if successful; i.e. no conflict. | |
1603 */ | |
1604 bool overloadInsert(Dsymbol s) | |
1605 { | |
1606 FuncDeclaration f; | |
1607 AliasDeclaration a; | |
1608 | |
1609 //writef("FuncDeclaration.overloadInsert(%s)\n", s.toChars()); | |
1610 a = s.isAliasDeclaration(); | |
1611 if (a) | |
1612 { | |
1613 if (overnext) | |
1614 return overnext.overloadInsert(a); | |
1615 | |
1616 if (!a.aliassym && a.type.ty != TY.Tident && a.type.ty != TY.Tinstance) | |
1617 { | |
1618 //writef("\ta = '%s'\n", a.type.toChars()); | |
1619 return false; | |
1620 } | |
1621 overnext = a; | |
1622 //printf("\ttrue: no conflict\n"); | |
1623 return true; | |
1624 } | |
1625 f = s.isFuncDeclaration(); | |
1626 if (!f) | |
1627 return false; | |
1628 | |
1629 static if (false) { | |
1630 /* Disable this check because: | |
1631 * const void foo(); | |
1632 * semantic() isn't run yet on foo(), so the const hasn't been | |
1633 * applied yet. | |
1634 */ | |
1635 if (type) | |
1636 { | |
1637 printf("type = %s\n", type.toChars()); | |
1638 printf("f.type = %s\n", f.type.toChars()); | |
1639 } | |
1640 if (type && f.type && // can be null for overloaded constructors | |
1641 f.type.covariant(type) && | |
1642 f.type.mod == type.mod && | |
1643 !isFuncAliasDeclaration()) | |
1644 { | |
1645 //printf("\tfalse: conflict %s\n", kind()); | |
1646 return false; | |
1647 } | |
1648 } | |
1649 | |
1650 if (overnext) | |
1651 return overnext.overloadInsert(f); | |
1652 overnext = f; | |
1653 //printf("\ttrue: no conflict\n"); | |
1654 return true; | |
1655 } | |
1656 | |
1657 FuncDeclaration overloadExactMatch(Type t) | |
1658 { | |
1659 Param1 p; | |
1660 p.t = t; | |
1661 p.f = null; | |
1662 overloadApply(this, &p.fp1); | |
1663 return p.f; | |
1664 } | |
1665 | |
1666 FuncDeclaration overloadResolve(Loc loc, Expression ethis, Expressions arguments, int flags = 0) | |
1667 { | |
1668 TypeFunction tf; | |
1669 Match m; | |
1670 | |
1671 static if (false) { | |
1672 printf("FuncDeclaration.overloadResolve('%s')\n", toChars()); | |
1673 if (arguments) | |
1674 { | |
1675 int i; | |
1676 | |
1677 for (i = 0; i < arguments.dim; i++) | |
1678 { | |
1679 Expression arg; | |
1680 | |
1681 arg = cast(Expression)arguments.data[i]; | |
1682 assert(arg.type); | |
1683 printf("\t%s: ", arg.toChars()); | |
1684 arg.type.print(); | |
1685 } | |
1686 } | |
1687 } | |
1688 | |
1689 m.last = MATCH.MATCHnomatch; | |
1690 overloadResolveX(&m, this, ethis, arguments); | |
1691 | |
1692 if (m.count == 1) // exactly one match | |
1693 { | |
1694 return m.lastf; | |
1695 } | |
1696 else | |
1697 { | |
1698 scope OutBuffer buf = new OutBuffer(); | |
1699 | |
1700 buf.writeByte('('); | |
1701 if (arguments) | |
1702 { | |
1703 HdrGenState hgs; | |
1704 | |
1705 argExpTypesToCBuffer(buf, arguments, &hgs); | |
1706 buf.writeByte(')'); | |
1707 if (ethis) | |
1708 ethis.type.modToBuffer(buf); | |
1709 } | |
1710 else | |
1711 buf.writeByte(')'); | |
1712 | |
1713 if (m.last == MATCH.MATCHnomatch) | |
1714 { | |
1715 if (flags & 1) // if do not print error messages | |
1716 return null; // no match | |
1717 | |
1718 tf = cast(TypeFunction)type; | |
1719 | |
1720 scope OutBuffer buf2 = new OutBuffer(); | |
1721 tf.modToBuffer(buf2); | |
1722 | |
1723 //printf("tf = %s, args = %s\n", tf.deco, ((Expression *)arguments.data[0]).type.deco); | |
1724 error(loc, "%s%s is not callable using argument types %s", | |
1725 Argument.argsTypesToChars(tf.parameters, tf.varargs), | |
1726 buf2.toChars(), | |
1727 buf.toChars()); | |
1728 return m.anyf; // as long as it's not a FuncAliasDeclaration | |
1729 } | |
1730 else | |
1731 { | |
1732 static if (true) { | |
1733 TypeFunction t1 = cast(TypeFunction)m.lastf.type; | |
1734 TypeFunction t2 = cast(TypeFunction)m.nextf.type; | |
1735 | |
1736 error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", | |
1737 buf.toChars(), | |
1738 m.lastf.toPrettyChars(), Argument.argsTypesToChars(t1.parameters, t1.varargs), | |
1739 m.nextf.toPrettyChars(), Argument.argsTypesToChars(t2.parameters, t2.varargs)); | |
1740 } else { | |
1741 error(loc, "overloads %s and %s both match argument list for %s", | |
1742 m.lastf.type.toChars(), | |
1743 m.nextf.type.toChars(), | |
1744 m.lastf.toChars()); | |
1745 } | |
1746 return m.lastf; | |
1747 } | |
1748 } | |
1749 } | |
1750 | |
1751 /************************************* | |
1752 * Determine partial specialization order of 'this' vs g. | |
1753 * This is very similar to TemplateDeclaration.leastAsSpecialized(). | |
1754 * Returns: | |
1755 * match 'this' is at least as specialized as g | |
1756 * 0 g is more specialized than 'this' | |
1757 */ | |
1758 MATCH leastAsSpecialized(FuncDeclaration g) | |
1759 { | |
1760 version (LOG_LEASTAS) { | |
1761 printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars()); | |
1762 } | |
1763 | |
1764 /* This works by calling g() with f()'s parameters, and | |
1765 * if that is possible, then f() is at least as specialized | |
1766 * as g() is. | |
1767 */ | |
1768 | |
1769 TypeFunction tf = cast(TypeFunction)type; | |
1770 TypeFunction tg = cast(TypeFunction)g.type; | |
1771 size_t nfparams = Argument.dim(tf.parameters); | |
1772 size_t ngparams = Argument.dim(tg.parameters); | |
1773 MATCH match = MATCHexact; | |
1774 | |
1775 /* If both functions have a 'this' pointer, and the mods are not | |
1776 * the same and g's is not const, then this is less specialized. | |
1777 */ | |
1778 if (needThis() && g.needThis()) | |
1779 { | |
1780 if (tf.mod != tg.mod) | |
1781 { | |
1782 if (tg.mod == MODconst) | |
1783 match = MATCHconst; | |
1784 else | |
1785 return MATCHnomatch; | |
1786 } | |
1787 } | |
1788 | |
1789 /* Create a dummy array of arguments out of the parameters to f() | |
1790 */ | |
1791 scope Expressions args = new Expressions(); | |
1792 args.setDim(nfparams); | |
1793 for (int u = 0; u < nfparams; u++) | |
1794 { | |
1795 Argument p = Argument.getNth(tf.parameters, u); | |
1796 Expression e; | |
1797 if (p.storageClass & (STCref | STCout)) | |
1798 { | |
1799 e = new IdentifierExp(Loc(0), p.ident); | |
1800 e.type = p.type; | |
1801 } | |
1802 else | |
1803 e = p.type.defaultInit(Loc(0)); | |
1804 | |
1805 args.data[u] = cast(void*)e; | |
1806 } | |
1807 | |
1808 MATCH m = cast(MATCH) tg.callMatch(null, args); | |
1809 if (m) | |
1810 { | |
1811 /* A variadic parameter list is less specialized than a | |
1812 * non-variadic one. | |
1813 */ | |
1814 if (tf.varargs && !tg.varargs) | |
1815 goto L1; // less specialized | |
1816 | |
1817 version (LOG_LEASTAS) { | |
1818 printf(" matches %d, so is least as specialized\n", m); | |
1819 } | |
1820 return m; | |
1821 } | |
1822 L1: | |
1823 version (LOG_LEASTAS) { | |
1824 printf(" doesn't match, so is not as specialized\n"); | |
1825 } | |
1826 return MATCHnomatch; | |
1827 } | |
1828 | |
1829 /******************************** | |
1830 * Labels are in a separate scope, one per function. | |
1831 */ | |
1832 LabelDsymbol searchLabel(Identifier ident) | |
1833 { | |
1834 Dsymbol s; | |
1835 | |
1836 if (!labtab) | |
1837 labtab = new DsymbolTable(); // guess we need one | |
1838 | |
1839 s = labtab.lookup(ident); | |
1840 if (!s) | |
1841 { | |
1842 s = new LabelDsymbol(ident); | |
1843 labtab.insert(s); | |
1844 } | |
1845 | |
1846 return cast(LabelDsymbol)s; | |
1847 } | |
1848 | |
1849 /**************************************** | |
1850 * If non-static member function that has a 'this' pointer, | |
1851 * return the aggregate it is a member of. | |
1852 * Otherwise, return null. | |
1853 */ | |
1854 AggregateDeclaration isThis() | |
1855 { | |
1856 AggregateDeclaration ad = null; | |
1857 | |
1858 //printf("+FuncDeclaration.isThis() '%s'\n", toChars()); | |
1859 if ((storage_class & STC.STCstatic) == 0) | |
1860 { | |
1861 ad = isMember2(); | |
1862 } | |
1863 //printf("-FuncDeclaration.isThis() %p\n", ad); | |
1864 return ad; | |
1865 } | |
1866 | |
1867 AggregateDeclaration isMember2() | |
1868 { | |
1869 AggregateDeclaration ad = null; | |
1870 | |
1871 //printf("+FuncDeclaration.isMember2() '%s'\n", toChars()); | |
1872 for (Dsymbol s = this; s; s = s.parent) | |
1873 { | |
1874 //printf("\ts = '%s', parent = '%s', kind = %s\n", s.toChars(), s.parent.toChars(), s.parent.kind()); | |
1875 ad = s.isMember(); | |
1876 if (ad) | |
1877 { //printf("test4\n"); | |
1878 break; | |
1879 } | |
1880 if (!s.parent || (!s.parent.isTemplateInstance())) | |
1881 { //printf("test5\n"); | |
1882 break; | |
1883 } | |
1884 } | |
1885 //printf("-FuncDeclaration.isMember2() %p\n", ad); | |
1886 return ad; | |
1887 } | |
1888 | |
1889 /***************************************** | |
1890 * Determine lexical level difference from 'this' to nested function 'fd'. | |
1891 * Error if this cannot call fd. | |
1892 * Returns: | |
1893 * 0 same level | |
1894 * -1 increase nesting by 1 (fd is nested within 'this') | |
1895 * >0 decrease nesting by number | |
1896 */ | |
1897 int getLevel(Loc loc, FuncDeclaration fd) // lexical nesting level difference | |
1898 { | |
1899 int level; | |
1900 Dsymbol s; | |
1901 Dsymbol fdparent; | |
1902 | |
1903 //printf("FuncDeclaration.getLevel(fd = '%s')\n", fd.toChars()); | |
1904 fdparent = fd.toParent2(); | |
1905 if (fdparent == this) | |
1906 return -1; | |
1907 s = this; | |
1908 level = 0; | |
1909 while (fd != s && fdparent != s.toParent2()) | |
1910 { | |
1911 //printf("\ts = '%s'\n", s.toChars()); | |
1912 FuncDeclaration thisfd = s.isFuncDeclaration(); | |
1913 if (thisfd) | |
1914 { | |
1915 if (!thisfd.isNested() && !thisfd.vthis) | |
1916 goto Lerr; | |
1917 } | |
1918 else | |
1919 { | |
1920 AggregateDeclaration thiscd = s.isAggregateDeclaration(); | |
1921 if (thiscd) | |
1922 { | |
1923 if (!thiscd.isNested()) | |
1924 goto Lerr; | |
1925 } | |
1926 else | |
1927 goto Lerr; | |
1928 } | |
1929 | |
1930 s = s.toParent2(); | |
1931 assert(s); | |
1932 level++; | |
1933 } | |
1934 return level; | |
1935 | |
1936 Lerr: | |
1937 error(loc, "cannot access frame of function %s", fd.toChars()); | |
1938 return 1; | |
1939 } | |
1940 | |
1941 void appendExp(Expression e) | |
1942 { | |
1943 assert(false); | |
1944 } | |
1945 | |
1946 void appendState(Statement s) | |
1947 { | |
1948 assert(false); | |
1949 } | |
1950 | |
1951 string mangle() | |
1952 out (result) | |
1953 { | |
1954 assert(result.length > 0); | |
1955 } | |
1956 body | |
1957 { | |
1958 if (isMain()) { | |
1959 return "_Dmain"; | |
1960 } | |
1961 | |
1962 if (isWinMain() || isDllMain() || ident == Id.tls_get_addr) | |
1963 return ident.toChars(); | |
1964 | |
1965 assert(this); | |
1966 | |
1967 return Declaration.mangle(); | |
1968 } | |
1969 | |
1970 string toPrettyChars() | |
1971 { | |
1972 if (isMain()) | |
1973 return "D main"; | |
1974 else | |
1975 return Dsymbol.toPrettyChars(); | |
1976 } | |
1977 | |
1978 int isMain() | |
1979 { | |
1980 return ident is Id.main && linkage != LINK.LINKc && !isMember() && !isNested(); | |
1981 } | |
1982 | |
1983 int isWinMain() | |
1984 { | |
1985 //printf("FuncDeclaration::isWinMain() %s\n", toChars()); | |
1986 static if (false) { | |
1987 int x = ident == Id.WinMain && | |
1988 linkage != LINK.LINKc && !isMember(); | |
1989 printf("%s\n", x ? "yes" : "no"); | |
1990 return x; | |
1991 } else { | |
1992 return ident == Id.WinMain && linkage != LINK.LINKc && !isMember(); | |
1993 } | |
1994 } | |
1995 | |
1996 int isDllMain() | |
1997 { | |
1998 return ident == Id.DllMain && linkage != LINK.LINKc && !isMember(); | |
1999 } | |
2000 | |
2001 /********************************** | |
2002 * Determine if function is a builtin one that we can | |
2003 * evaluate at compile time. | |
2004 */ | |
2005 BUILTIN isBuiltin() | |
2006 { | |
2007 static string FeZe = "FNaNbeZe"; // pure nothrow real function(real) | |
2008 | |
2009 //printf("FuncDeclaration::isBuiltin() %s\n", toChars()); | |
2010 if (builtin == BUILTIN.BUILTINunknown) | |
2011 { | |
2012 builtin = BUILTIN.BUILTINnot; | |
2013 if (parent && parent.isModule()) | |
2014 { | |
2015 // If it's in the std.math package | |
2016 if (parent.ident == Id.math && parent.parent && parent.parent.ident == Id.std && !parent.parent.parent) | |
2017 { | |
2018 //printf("deco = %s\n", type.deco); | |
2019 if (type.deco == FeZe) | |
2020 { | |
2021 if (ident == Id.sin) | |
2022 builtin = BUILTIN.BUILTINsin; | |
2023 else if (ident == Id.cos) | |
2024 builtin = BUILTIN.BUILTINcos; | |
2025 else if (ident == Id.tan) | |
2026 builtin = BUILTIN.BUILTINtan; | |
2027 else if (ident == Id._sqrt) | |
2028 builtin = BUILTIN.BUILTINsqrt; | |
2029 else if (ident == Id.fabs) | |
2030 builtin = BUILTIN.BUILTINfabs; | |
2031 //printf("builtin = %d\n", builtin); | |
2032 } | |
2033 // if float or double versions | |
2034 else if (type.deco == "FNaNbdZd" || type.deco == "FNaNbfZf") | |
2035 { | |
2036 if (ident == Id._sqrt) | |
2037 builtin = BUILTIN.BUILTINsqrt; | |
2038 } | |
2039 } | |
2040 } | |
2041 } | |
2042 | |
2043 return builtin; | |
2044 } | |
2045 | |
2046 bool isExport() | |
2047 { | |
2048 return protection == PROT.PROTexport; | |
2049 } | |
2050 | |
2051 bool isImportedSymbol() | |
2052 { | |
2053 //printf("isImportedSymbol()\n"); | |
2054 //printf("protection = %d\n", protection); | |
2055 return (protection == PROT.PROTexport) && !fbody; | |
2056 } | |
2057 | |
2058 bool isAbstract() | |
2059 { | |
2060 return (storage_class & STC.STCabstract) != 0; | |
2061 } | |
2062 | |
2063 bool isCodeseg() | |
2064 { | |
2065 assert(false); | |
2066 } | |
2067 | |
2068 bool isOverloadable() | |
2069 { | |
2070 assert(false); | |
2071 } | |
2072 | |
2073 bool isPure() | |
2074 { | |
2075 //printf("FuncDeclaration::isPure() '%s'\n", toChars()); | |
2076 assert(type.ty == TY.Tfunction); | |
2077 return (cast(TypeFunction)this.type).ispure; | |
2078 } | |
2079 | |
2080 bool isNested() | |
2081 { | |
2082 //if (!toParent()) | |
2083 //printf("FuncDeclaration.isNested('%s') parent=%p\n", toChars(), parent); | |
2084 //printf("\ttoParent2() = '%s'\n", toParent2().toChars()); | |
2085 return ((storage_class & STC.STCstatic) == 0) && | |
2086 (toParent2().isFuncDeclaration() !is null); | |
2087 } | |
2088 | |
2089 bool needThis() | |
2090 { | |
2091 //printf("FuncDeclaration.needThis() '%s'\n", toChars()); | |
2092 bool needThis = isThis() !is null; | |
2093 | |
2094 //printf("\t%d\n", i); | |
2095 if (!needThis) { | |
2096 if (auto fa = isFuncAliasDeclaration()) { | |
2097 needThis = fa.funcalias.needThis(); | |
2098 } | |
2099 } | |
2100 | |
2101 return needThis; | |
2102 } | |
2103 | |
2104 bool isVirtual() | |
2105 { | |
2106 static if (false) { | |
2107 printf("FuncDeclaration.isVirtual(%s)\n", toChars()); | |
2108 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROT.PROTprivate, isCtorDeclaration(), linkage != LINK.LINKd); | |
2109 printf("result is %d\n", | |
2110 isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && toParent().isClassDeclaration()); | |
2111 } | |
2112 return isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && toParent().isClassDeclaration(); | |
2113 } | |
2114 | |
2115 int isFinal() | |
2116 { | |
2117 ClassDeclaration cd; | |
2118 static if (false) { | |
2119 printf("FuncDeclaration.isFinal(%s)\n", toChars()); | |
2120 printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROT.PROTprivate, isCtorDeclaration(), linkage != LINK.LINKd); | |
2121 printf("result is %d\n", | |
2122 isMember() && !(isStatic() || protection == PROT.PROTprivate || protection == PROT.PROTpackage) && (cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.STCfinal); | |
2123 } | |
2124 return isMember() && (Declaration.isFinal() || ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.STCfinal)); | |
2125 } | |
2126 | |
2127 bool addPreInvariant() | |
2128 { | |
2129 AggregateDeclaration ad = isThis(); | |
2130 return (ad && | |
2131 //ad.isClassDeclaration() && | |
2132 global.params.useInvariants && | |
2133 (protection == PROT.PROTpublic || protection == PROT.PROTexport) && | |
2134 !naked && | |
2135 ident !is Id.cpctor); | |
2136 } | |
2137 | |
2138 bool addPostInvariant() | |
2139 { | |
2140 AggregateDeclaration ad = isThis(); | |
2141 return (ad && ad.inv && | |
2142 //ad.isClassDeclaration() && | |
2143 global.params.useInvariants && | |
2144 (protection == PROT.PROTpublic || protection == PROT.PROTexport) && | |
2145 !naked && | |
2146 ident !is Id.cpctor); | |
2147 } | |
2148 | |
2149 Expression interpret(InterState* istate, Expressions arguments, Expression thisexp = null) | |
2150 { | |
2151 assert(false); | |
2152 } | |
2153 | |
2154 void inlineScan() | |
2155 { | |
2156 InlineScanState iss; | |
2157 | |
2158 version (LOG) { | |
2159 printf("FuncDeclaration.inlineScan('%s')\n", toChars()); | |
2160 } | |
2161 ///memset(&iss, 0, sizeof(iss)); | |
2162 iss.fd = this; | |
2163 if (fbody) | |
2164 { | |
2165 inlineNest++; | |
2166 fbody = fbody.inlineScan(&iss); | |
2167 inlineNest--; | |
2168 } | |
2169 } | |
2170 | |
2171 int canInline(int hasthis, int hdrscan = 0) | |
2172 { | |
2173 int cost; | |
2174 | |
2175 // #define CANINLINE_LOG 0 | |
2176 | |
2177 version (CANINLINE_LOG) { | |
2178 printf("FuncDeclaration.canInline(hasthis = %d, '%s')\n", hasthis, toChars()); | |
2179 } | |
2180 | |
2181 if (needThis() && !hasthis) | |
2182 return 0; | |
2183 | |
2184 if (inlineNest || (semanticRun < 3 && !hdrscan)) | |
2185 { | |
2186 version (CANINLINE_LOG) { | |
2187 printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); | |
2188 } | |
2189 return 0; | |
2190 } | |
2191 | |
2192 switch (inlineStatus) | |
2193 { | |
2194 case ILS.ILSyes: | |
2195 version (CANINLINE_LOG) { | |
2196 printf("\t1: yes %s\n", toChars()); | |
2197 } | |
2198 return 1; | |
2199 | |
2200 case ILS.ILSno: | |
2201 version (CANINLINE_LOG) { | |
2202 printf("\t1: no %s\n", toChars()); | |
2203 } | |
2204 return 0; | |
2205 | |
2206 case ILS.ILSuninitialized: | |
2207 break; | |
2208 | |
2209 default: | |
2210 assert(0); | |
2211 } | |
2212 | |
2213 if (type) | |
2214 { | |
2215 assert(type.ty == Tfunction); | |
2216 TypeFunction tf = cast(TypeFunction)type; | |
2217 if (tf.varargs == 1) // no variadic parameter lists | |
2218 goto Lno; | |
2219 | |
2220 /* Don't inline a function that returns non-void, but has | |
2221 * no return expression. | |
2222 */ | |
2223 if (tf.next && tf.next.ty != Tvoid && | |
2224 !(hasReturnExp & 1) && | |
2225 !hdrscan) | |
2226 goto Lno; | |
2227 } | |
2228 else | |
2229 { | |
2230 CtorDeclaration ctor = isCtorDeclaration(); | |
2231 if (ctor && ctor.varargs == 1) | |
2232 goto Lno; | |
2233 } | |
2234 | |
2235 if ( | |
2236 !fbody || | |
2237 !hdrscan && | |
2238 ( | |
2239 /// static if (false) { | |
2240 /// isCtorDeclaration() || // cannot because need to convert: | |
2241 /// // return; | |
2242 /// // to: | |
2243 /// // return this; | |
2244 /// } | |
2245 isSynchronized() || | |
2246 isImportedSymbol() || | |
2247 /// version (DMDV2) { | |
2248 closureVars.dim || // no nested references to this frame | |
2249 /// } else { | |
2250 /// nestedFrameRef || // no nested references to this frame | |
2251 /// } | |
2252 (isVirtual() && !isFinal()) | |
2253 )) | |
2254 { | |
2255 goto Lno; | |
2256 } | |
2257 | |
2258 /* If any parameters are Tsarray's (which are passed by reference) | |
2259 * or out parameters (also passed by reference), don't do inlining. | |
2260 */ | |
2261 if (parameters) | |
2262 { | |
2263 for (int i = 0; i < parameters.dim; i++) | |
2264 { | |
2265 VarDeclaration v = cast(VarDeclaration)parameters.data[i]; | |
2266 if (v.isOut() || v.isRef() || v.type.toBasetype().ty == Tsarray) | |
2267 goto Lno; | |
2268 } | |
2269 } | |
2270 | |
2271 InlineCostState ics; | |
2272 ///memset(&ics, 0, sizeof(ics)); | |
2273 ics.hasthis = hasthis; | |
2274 ics.fd = this; | |
2275 ics.hdrscan = hdrscan; | |
2276 cost = fbody.inlineCost(&ics); | |
2277 version (CANINLINE_LOG) { | |
2278 printf("cost = %d\n", cost); | |
2279 } | |
2280 if (cost >= COST_MAX) | |
2281 goto Lno; | |
2282 | |
2283 if (!hdrscan) // Don't scan recursively for header content scan | |
2284 inlineScan(); | |
2285 | |
2286 Lyes: | |
2287 if (!hdrscan) // Don't modify inlineStatus for header content scan | |
2288 inlineStatus = ILS.ILSyes; | |
2289 version (CANINLINE_LOG) { | |
2290 printf("\t2: yes %s\n", toChars()); | |
2291 } | |
2292 return 1; | |
2293 | |
2294 Lno: | |
2295 if (!hdrscan) // Don't modify inlineStatus for header content scan | |
2296 inlineStatus = ILS.ILSno; | |
2297 version (CANINLINE_LOG) { | |
2298 printf("\t2: no %s\n", toChars()); | |
2299 } | |
2300 return 0; | |
2301 } | |
2302 | |
2303 Expression doInline(InlineScanState* iss, Expression ethis, Array arguments) | |
2304 { | |
2305 InlineDoState ids = new InlineDoState(); | |
2306 DeclarationExp de; | |
2307 Expression e = null; | |
2308 | |
2309 version (LOG) { | |
2310 printf("FuncDeclaration.doInline('%s')\n", toChars()); | |
2311 } | |
2312 | |
2313 ///memset(&ids, 0, sizeof(ids)); | |
2314 ids.parent = iss.fd; | |
2315 | |
2316 // Set up vthis | |
2317 if (ethis) | |
2318 { | |
2319 VarDeclaration vthis; | |
2320 ExpInitializer ei; | |
2321 VarExp ve; | |
2322 | |
2323 version (STRUCTTHISREF) { | |
2324 if (ethis.type.ty == Tpointer) | |
2325 { | |
2326 Type t = ethis.type.nextOf(); | |
2327 ethis = new PtrExp(ethis.loc, ethis); | |
2328 ethis.type = t; | |
2329 } | |
2330 ei = new ExpInitializer(ethis.loc, ethis); | |
2331 | |
2332 vthis = new VarDeclaration(ethis.loc, ethis.type, Id.This, ei); | |
2333 if (ethis.type.ty != Tclass) | |
2334 vthis.storage_class = STCref; | |
2335 else | |
2336 vthis.storage_class = STCin; | |
2337 } else { | |
2338 if (ethis.type.ty != Tclass && ethis.type.ty != Tpointer) | |
2339 { | |
2340 ethis = ethis.addressOf(null); | |
2341 } | |
2342 | |
2343 ei = new ExpInitializer(ethis.loc, ethis); | |
2344 | |
2345 vthis = new VarDeclaration(ethis.loc, ethis.type, Id.This, ei); | |
2346 vthis.storage_class = STCin; | |
2347 } | |
2348 vthis.linkage = LINKd; | |
2349 vthis.parent = iss.fd; | |
2350 | |
2351 ve = new VarExp(vthis.loc, vthis); | |
2352 ve.type = vthis.type; | |
2353 | |
2354 ei.exp = new AssignExp(vthis.loc, ve, ethis); | |
2355 ei.exp.type = ve.type; | |
2356 version (STRUCTTHISREF) { | |
2357 if (ethis.type.ty != Tclass) | |
2358 { | |
2359 /* This is a reference initialization, not a simple assignment. | |
2360 */ | |
2361 ei.exp.op = TOKconstruct; | |
2362 } | |
2363 } | |
2364 | |
2365 ids.vthis = vthis; | |
2366 } | |
2367 | |
2368 // Set up parameters | |
2369 if (ethis) | |
2370 { | |
2371 e = new DeclarationExp(Loc(0), ids.vthis); | |
2372 e.type = Type.tvoid; | |
2373 } | |
2374 | |
2375 if (arguments && arguments.dim) | |
2376 { | |
2377 assert(parameters.dim == arguments.dim); | |
2378 | |
2379 for (int i = 0; i < arguments.dim; i++) | |
2380 { | |
2381 VarDeclaration vfrom = cast(VarDeclaration)parameters.data[i]; | |
2382 VarDeclaration vto; | |
2383 Expression arg = cast(Expression)arguments.data[i]; | |
2384 ExpInitializer ei; | |
2385 VarExp ve; | |
2386 | |
2387 ei = new ExpInitializer(arg.loc, arg); | |
2388 | |
2389 vto = new VarDeclaration(vfrom.loc, vfrom.type, vfrom.ident, ei); | |
2390 vto.storage_class |= vfrom.storage_class & (STCin | STCout | STClazy | STCref); | |
2391 vto.linkage = vfrom.linkage; | |
2392 vto.parent = iss.fd; | |
2393 //printf("vto = '%s', vto.storage_class = x%x\n", vto.toChars(), vto.storage_class); | |
2394 //printf("vto.parent = '%s'\n", iss.fd.toChars()); | |
2395 | |
2396 ve = new VarExp(vto.loc, vto); | |
2397 //ve.type = vto.type; | |
2398 ve.type = arg.type; | |
2399 | |
2400 ei.exp = new AssignExp(vto.loc, ve, arg); | |
2401 ei.exp.type = ve.type; | |
2402 //ve.type.print(); | |
2403 //arg.type.print(); | |
2404 //ei.exp.print(); | |
2405 | |
2406 ids.from.push(cast(void*)vfrom); | |
2407 ids.to.push(cast(void*)vto); | |
2408 | |
2409 de = new DeclarationExp(Loc(0), vto); | |
2410 de.type = Type.tvoid; | |
2411 | |
2412 e = Expression.combine(e, de); | |
2413 } | |
2414 } | |
2415 | |
2416 inlineNest++; | |
2417 Expression eb = fbody.doInline(ids); | |
2418 inlineNest--; | |
2419 //eb.type.print(); | |
2420 //eb.print(); | |
2421 //eb.dump(0); | |
2422 return Expression.combine(e, eb); | |
2423 } | |
2424 | |
2425 string kind() | |
2426 { | |
2427 return "function"; | |
2428 } | |
2429 | |
2430 void toDocBuffer(OutBuffer buf) | |
2431 { | |
2432 assert(false); | |
2433 } | |
2434 | |
2435 FuncDeclaration isUnique() | |
2436 { | |
2437 assert(false); | |
2438 } | |
2439 | |
2440 /******************************* | |
2441 * Look at all the variables in this function that are referenced | |
2442 * by nested functions, and determine if a closure needs to be | |
2443 * created for them. | |
2444 */ | |
2445 bool needsClosure() | |
2446 { | |
2447 /* Need a closure for all the closureVars[] if any of the | |
2448 * closureVars[] are accessed by a | |
2449 * function that escapes the scope of this function. | |
2450 * We take the conservative approach and decide that any function that: | |
2451 * 1) is a virtual function | |
2452 * 2) has its address taken | |
2453 * 3) has a parent that escapes | |
2454 * | |
2455 * Note that since a non-virtual function can be called by | |
2456 * a virtual one, if that non-virtual function accesses a closure | |
2457 * var, the closure still has to be taken. Hence, we check for isThis() | |
2458 * instead of isVirtual(). (thanks to David Friedman) | |
2459 */ | |
2460 | |
2461 //printf("FuncDeclaration.needsClosure() %s\n", toChars()); | |
2462 for (int i = 0; i < closureVars.dim; i++) | |
2463 { | |
2464 VarDeclaration v = cast(VarDeclaration)closureVars.data[i]; | |
2465 assert(v.isVarDeclaration()); | |
2466 //printf("\tv = %s\n", v.toChars()); | |
2467 | |
2468 for (int j = 0; j < v.nestedrefs.dim; j++) | |
2469 { FuncDeclaration f = cast(FuncDeclaration)v.nestedrefs.data[j]; | |
2470 assert(f != this); | |
2471 | |
2472 //printf("\t\tf = %s, %d, %p, %d\n", f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf); | |
2473 if (f.isThis() || f.tookAddressOf) | |
2474 goto Lyes; // assume f escapes this function's scope | |
2475 | |
2476 // Look to see if any parents of f that are below this escape | |
2477 for (Dsymbol s = f.parent; s && s !is this; s = s.parent) | |
2478 { | |
2479 f = s.isFuncDeclaration(); | |
2480 if (f && (f.isThis() || f.tookAddressOf)) { | |
2481 goto Lyes; | |
2482 } | |
2483 } | |
2484 } | |
2485 } | |
2486 return false; | |
2487 | |
2488 Lyes: | |
2489 //printf("\tneeds closure\n"); | |
2490 return true; | |
2491 } | |
2492 | |
2493 static FuncDeclaration genCfunc(Type treturn, string name) | |
2494 { | |
2495 return genCfunc(treturn, Lexer.idPool(name)); | |
2496 } | |
2497 | |
2498 /********************************** | |
2499 * Generate a FuncDeclaration for a runtime library function. | |
2500 */ | |
2501 static FuncDeclaration genCfunc(Type treturn, Identifier id) | |
2502 { | |
2503 FuncDeclaration fd; | |
2504 TypeFunction tf; | |
2505 Dsymbol s; | |
2506 static DsymbolTable st = null; | |
2507 | |
2508 //printf("genCfunc(name = '%s')\n", id.toChars()); | |
2509 //printf("treturn\n\t"); treturn.print(); | |
2510 | |
2511 // See if already in table | |
2512 if (!st) | |
2513 st = new DsymbolTable(); | |
2514 | |
2515 s = st.lookup(id); | |
2516 if (s) | |
2517 { | |
2518 fd = s.isFuncDeclaration(); | |
2519 assert(fd); | |
2520 assert(fd.type.nextOf().equals(treturn)); | |
2521 } | |
2522 else | |
2523 { | |
2524 tf = new TypeFunction(null, treturn, 0, LINK.LINKc); | |
2525 fd = new FuncDeclaration(Loc(0), Loc(0), id, STCstatic, tf); | |
2526 fd.protection = PROT.PROTpublic; | |
2527 fd.linkage = LINK.LINKc; | |
2528 | |
2529 st.insert(fd); | |
2530 } | |
2531 return fd; | |
2532 } | |
2533 | |
2534 Symbol* toSymbol() | |
2535 { | |
2536 if (!csym) | |
2537 { | |
2538 Symbol* s; | |
2539 TYPE* t; | |
2540 string id; | |
2541 | |
2542 static if (false) { | |
2543 id = ident.toChars(); | |
2544 } else { | |
2545 id = mangle(); | |
2546 } | |
2547 //writef("FuncDeclaration.toSymbol(%s %s)\n", kind(), toChars()); | |
2548 //writef("\tid = '%s'\n", id); | |
2549 //writef("\ttype = %s\n", type.toChars()); | |
2550 s = symbol_calloc(toStringz(id)); | |
2551 slist_add(s); | |
2552 | |
2553 { | |
2554 s.prettyIdent = toStringz(toPrettyChars()); | |
2555 s.Sclass = SC.SCglobal; | |
2556 symbol_func(s); | |
2557 func_t* f = s.Sfunc; | |
2558 if (isVirtual()) | |
2559 f.Fflags |= F.Fvirtual; | |
2560 else if (isMember2()) | |
2561 f.Fflags |= F.Fstatic; | |
2562 f.Fstartline.Slinnum = loc.linnum; | |
2563 f.Fstartline.Sfilename = cast(char*)toStringz(loc.filename); | |
2564 if (endloc.linnum) | |
2565 { | |
2566 f.Fendline.Slinnum = endloc.linnum; | |
2567 f.Fendline.Sfilename = cast(char*)toStringz(endloc.filename); | |
2568 } | |
2569 else | |
2570 { | |
2571 f.Fendline.Slinnum = loc.linnum; | |
2572 f.Fendline.Sfilename = cast(char*)toStringz(loc.filename); | |
2573 } | |
2574 t = type.toCtype(); | |
2575 } | |
2576 | |
2577 mangle_t msave = t.Tmangle; | |
2578 if (isMain()) | |
2579 { | |
2580 t.Tty = TYM.TYnfunc; | |
2581 t.Tmangle = mTYman.mTYman_c; | |
2582 } | |
2583 else | |
2584 { | |
2585 switch (linkage) | |
2586 { | |
2587 case LINK.LINKwindows: | |
2588 t.Tmangle = mTYman.mTYman_std; | |
2589 break; | |
2590 | |
2591 case LINK.LINKpascal: | |
2592 t.Tty = TYM.TYnpfunc; | |
2593 t.Tmangle = mTYman.mTYman_pas; | |
2594 break; | |
2595 | |
2596 case LINK.LINKc: | |
2597 t.Tmangle = mTYman.mTYman_c; | |
2598 break; | |
2599 | |
2600 case LINK.LINKd: | |
2601 t.Tmangle = mTYman.mTYman_d; | |
2602 break; | |
2603 | |
2604 case LINK.LINKcpp: | |
2605 { t.Tmangle = mTYman.mTYman_cpp; | |
2606 version (TARGET_WINDOS) { | |
2607 if (isThis()) | |
2608 t.Tty = TYM.TYmfunc; | |
2609 } | |
2610 s.Sflags |= SFL.SFLpublic; | |
2611 Dsymbol parent = toParent(); | |
2612 ClassDeclaration cd = parent.isClassDeclaration(); | |
2613 if (cd) | |
2614 { | |
2615 .type* tt = cd.type.toCtype(); | |
2616 s.Sscope = tt.Tnext.Ttag; | |
2617 } | |
2618 break; | |
2619 } | |
2620 default: | |
2621 writef("linkage = %d\n", linkage); | |
2622 assert(0); | |
2623 } | |
2624 } | |
2625 if (msave) | |
2626 assert(msave == t.Tmangle); | |
2627 //printf("Tty = %x, mangle = x%x\n", t.Tty, t.Tmangle); | |
2628 t.Tcount++; | |
2629 s.Stype = t; | |
2630 //s.Sfielddef = this; | |
2631 | |
2632 csym = s; | |
2633 } | |
2634 return csym; | |
2635 } | |
2636 | |
2637 Symbol* toThunkSymbol(int offset) // thunk version | |
2638 { | |
2639 Symbol *sthunk; | |
2640 | |
2641 toSymbol(); | |
2642 | |
2643 static if (false) { | |
2644 char *id; | |
2645 char *n; | |
2646 type *t; | |
2647 | |
2648 n = sym.Sident; | |
14
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
2649 version (Bug4054) |
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
2650 id = cast(char*) GC.malloc(8 + 5 + strlen(n) + 1); |
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
2651 else |
0 | 2652 id = cast(char*) alloca(8 + 5 + strlen(n) + 1); |
2653 sprintf(id, "_thunk%d__%s", offset, n); | |
2654 s = symbol_calloc(id); | |
2655 slist_add(s); | |
2656 s.Stype = csym.Stype; | |
2657 s.Stype.Tcount++; | |
2658 } | |
2659 sthunk = symbol_generate(SCstatic, csym.Stype); | |
2660 sthunk.Sflags |= SFLimplem; | |
2661 cod3_thunk(sthunk, csym, 0, TYnptr, -offset, -1, 0); | |
2662 return sthunk; | |
2663 } | |
2664 | |
2665 void toObjFile(int multiobj) // compile to .obj file | |
2666 { | |
2667 Symbol* s; | |
2668 func_t* f; | |
2669 Symbol* senter; | |
2670 Symbol* sexit; | |
2671 | |
2672 FuncDeclaration func = this; | |
2673 ClassDeclaration cd = func.parent.isClassDeclaration(); | |
2674 int reverse; | |
2675 int i; | |
2676 int has_arguments; | |
2677 | |
2678 //printf("FuncDeclaration.toObjFile(%p, %s.%s)\n", func, parent.toChars(), func.toChars()); | |
2679 static if (false) { | |
2680 //printf("line = %d\n",func.getWhere() / LINEINC); | |
2681 EEcontext ee = env.getEEcontext(); | |
2682 if (ee.EEcompile == 2) | |
2683 { | |
2684 if (ee.EElinnum < (func.getWhere() / LINEINC) || | |
2685 ee.EElinnum > (func.endwhere / LINEINC) | |
2686 ) | |
2687 return; // don't compile this function | |
2688 ee.EEfunc = func.toSymbol(); | |
2689 } | |
2690 } | |
2691 | |
2692 if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration()) | |
2693 { | |
2694 obj_append(this); | |
2695 return; | |
2696 } | |
2697 | |
2698 if (semanticRun >= 5) // if toObjFile() already run | |
2699 return; | |
2700 | |
2701 semanticRun = 5; | |
2702 | |
2703 if (!func.fbody) | |
2704 { | |
2705 return; | |
2706 } | |
2707 | |
2708 if (func.isUnitTestDeclaration() && !global.params.useUnitTests) | |
2709 return; | |
2710 | |
2711 if (global.params.verbose) | |
2712 writef("function %s\n",func.toChars()); | |
2713 | |
2714 s = func.toSymbol(); | |
2715 f = s.Sfunc; | |
2716 | |
2717 version (TARGET_OSX) { | |
2718 s.Sclass = SC.SCcomdat; | |
2719 } else { | |
2720 s.Sclass = SC.SCglobal; | |
2721 } | |
2722 | |
2723 for (Dsymbol p = parent; p; p = p.parent) | |
2724 { | |
2725 if (p.isTemplateInstance()) | |
2726 { | |
2727 s.Sclass = SC.SCcomdat; | |
2728 break; | |
2729 } | |
2730 } | |
2731 | |
2732 if (isNested()) | |
2733 { | |
2734 // if (!(config.flags3 & CFG3pic)) | |
2735 // s.Sclass = SCstatic; | |
2736 f.Fflags3 |= F3.Fnested; | |
2737 } | |
2738 else | |
2739 { | |
2740 const(char)* libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; | |
2741 | |
2742 // Pull in RTL startup code | |
2743 if (func.isMain()) | |
2744 { objextdef("_main"); | |
2745 version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS | |
2746 obj_ehsections(); // initialize exception handling sections | |
2747 } else { | |
2748 objextdef("__acrtused_con"); | |
2749 } | |
2750 obj_includelib(libname); | |
2751 s.Sclass = SC.SCglobal; | |
2752 } | |
2753 else if (strcmp(s.Sident.ptr, "main".ptr) == 0 && linkage == LINK.LINKc) | |
2754 s.Sclass = SC.SCglobal; | |
2755 | |
2756 else if (func.isWinMain()) | |
2757 { | |
2758 objextdef("__acrtused"); | |
2759 obj_includelib(libname); | |
2760 s.Sclass = SC.SCglobal; | |
2761 } | |
2762 | |
2763 // Pull in RTL startup code | |
2764 else if (func.isDllMain()) | |
2765 { | |
2766 objextdef("__acrtused_dll"); | |
2767 obj_includelib(libname); | |
2768 s.Sclass = SC.SCglobal; | |
2769 } | |
2770 } | |
2771 | |
2772 cstate.CSpsymtab = &f.Flocsym; | |
2773 | |
2774 // Find module m for this function | |
2775 Module m = null; | |
2776 for (Dsymbol p = parent; p; p = p.parent) | |
2777 { | |
2778 m = p.isModule(); | |
2779 if (m) | |
2780 break; | |
2781 } | |
2782 | |
2783 IRState irs = IRState(m, func); | |
2784 Array deferToObj = new Array(); // write these to OBJ file later | |
2785 irs.deferToObj = deferToObj; | |
2786 | |
2787 TypeFunction tf; | |
2788 RET retmethod; | |
2789 Symbol* shidden = null; | |
2790 Symbol* sthis = null; | |
2791 tym_t tyf; | |
2792 | |
2793 tyf = tybasic(s.Stype.Tty); | |
2794 //printf("linkage = %d, tyf = x%x\n", linkage, tyf); | |
2795 reverse = tyrevfunc(s.Stype.Tty); | |
2796 | |
2797 assert(func.type.ty == TY.Tfunction); | |
2798 tf = cast(TypeFunction)(func.type); | |
2799 has_arguments = (tf.linkage == LINK.LINKd) && (tf.varargs == 1); | |
2800 retmethod = tf.retStyle(); | |
2801 if (retmethod == RET.RETstack) | |
2802 { | |
2803 // If function returns a struct, put a pointer to that | |
2804 // as the first argument | |
2805 .type* thidden = tf.next.pointerTo().toCtype(); | |
2806 char hiddenparam[5+4+1]; | |
2807 static int hiddenparami; // how many we've generated so far | |
2808 | |
2809 sprintf(hiddenparam.ptr, "__HID%d".ptr, ++hiddenparami); | |
2810 shidden = symbol_name(hiddenparam.ptr, SC.SCparameter, thidden); | |
2811 shidden.Sflags |= SFL.SFLtrue | SFL.SFLfree; | |
2812 | |
2813 version (DMDV1) { | |
2814 bool nestedref = func.nrvo_can && func.nrvo_var && func.nrvo_var.nestedref; | |
2815 } else { | |
2816 bool nestedref = func.nrvo_can && func.nrvo_var && (func.nrvo_var.nestedrefs.dim != 0); | |
2817 } | |
2818 if (nestedref) { | |
2819 type_setcv(&shidden.Stype, shidden.Stype.Tty | mTY.mTYvolatile); | |
2820 } | |
2821 | |
2822 irs.shidden = shidden; | |
2823 this.shidden = shidden; | |
2824 } | |
2825 | |
2826 if (vthis) | |
2827 { | |
2828 assert(!vthis.csym); | |
2829 sthis = vthis.toSymbol(); | |
2830 irs.sthis = sthis; | |
2831 if (!(f.Fflags3 & F3.Fnested)) | |
2832 f.Fflags3 |= F3.Fmember; | |
2833 } | |
2834 | |
2835 Symbol** params; | |
2836 uint pi; | |
2837 | |
2838 // Estimate number of parameters, pi | |
2839 pi = (v_arguments !is null); | |
2840 if (parameters) | |
2841 pi += parameters.dim; | |
2842 | |
2843 // Allow extra 2 for sthis and shidden | |
14
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
2844 version (Bug4054) |
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
2845 params = cast(Symbol**)GC.malloc((pi + 2) * (Symbol*).sizeof); |
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
2846 else |
0 | 2847 params = cast(Symbol**)alloca((pi + 2) * (Symbol*).sizeof); |
2848 | |
2849 // Get the actual number of parameters, pi, and fill in the params[] | |
2850 pi = 0; | |
2851 if (v_arguments) | |
2852 { | |
2853 params[pi] = v_arguments.toSymbol(); | |
2854 pi += 1; | |
2855 } | |
2856 if (parameters) | |
2857 { | |
2858 for (i = 0; i < parameters.dim; i++) | |
2859 { | |
2860 VarDeclaration v = cast(VarDeclaration)parameters.data[i]; | |
2861 debug { | |
2862 if (v.csym) | |
2863 writef("parameter '%s'\n", v.toChars()); | |
2864 } | |
2865 assert(!v.csym); | |
2866 params[pi + i] = v.toSymbol(); | |
2867 } | |
2868 pi += i; | |
2869 } | |
2870 | |
2871 if (reverse) | |
2872 { | |
2873 // Reverse params[] entries | |
2874 for (i = 0; i < pi/2; i++) | |
2875 { | |
2876 Symbol* sptmp = params[i]; | |
2877 params[i] = params[pi - 1 - i]; | |
2878 params[pi - 1 - i] = sptmp; | |
2879 } | |
2880 } | |
2881 | |
2882 if (shidden) | |
2883 { | |
2884 static if (false) { | |
2885 // shidden becomes last parameter | |
2886 params[pi] = shidden; | |
2887 } else { | |
2888 // shidden becomes first parameter | |
2889 memmove(params + 1, params, pi * (*params).sizeof); | |
2890 params[0] = shidden; | |
2891 } | |
2892 pi++; | |
2893 } | |
2894 | |
2895 | |
2896 if (sthis) | |
2897 { | |
2898 static if (false) { | |
2899 // sthis becomes last parameter | |
2900 params[pi] = sthis; | |
2901 } else { | |
2902 // sthis becomes first parameter | |
2903 memmove(params + 1, params, pi * (*params).sizeof); | |
2904 params[0] = sthis; | |
2905 } | |
2906 pi++; | |
2907 } | |
2908 | |
2909 if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && | |
2910 linkage != LINK.LINKd && shidden && sthis) | |
2911 { | |
2912 /* swap shidden and sthis | |
2913 */ | |
2914 Symbol* sp = params[0]; | |
2915 params[0] = params[1]; | |
2916 params[1] = sp; | |
2917 } | |
2918 | |
2919 for (i = 0; i < pi; i++) | |
2920 { | |
2921 Symbol *sp = params[i]; | |
2922 sp.Sclass = SC.SCparameter; | |
2923 sp.Sflags &= ~SFL.SFLspill; | |
2924 sp.Sfl = FL.FLpara; | |
2925 symbol_add(sp); | |
2926 } | |
2927 | |
2928 // First parameter goes in register | |
2929 if (pi) | |
2930 { | |
2931 Symbol* sp = params[0]; | |
2932 if ((tyf == TYM.TYjfunc || tyf == TYM.TYmfunc) && type_jparam(sp.Stype)) | |
2933 { | |
2934 sp.Sclass = SC.SCfastpar; | |
2935 sp.Spreg = (tyf == TYM.TYjfunc) ? REG.AX : REG.CX; | |
2936 sp.Sfl = FL.FLauto; | |
2937 //printf("'%s' is SCfastpar\n",sp.Sident); | |
2938 } | |
2939 } | |
2940 | |
2941 if (func.fbody) | |
2942 { | |
2943 block* b; | |
2944 Blockx bx; | |
2945 Statement sbody; | |
2946 | |
2947 localgot = null; | |
2948 | |
2949 sbody = func.fbody; | |
2950 ///memset(&bx, 0, (bx).sizeof); | |
2951 bx.startblock = block_calloc(); | |
2952 bx.curblock = bx.startblock; | |
2953 bx.funcsym = s; | |
2954 bx.scope_index = -1; | |
2955 bx.classdec = cd; | |
2956 bx.member = func; | |
2957 bx.module_ = getModule(); | |
2958 irs.blx = &bx; | |
2959 | |
2960 buildClosure(&irs); | |
2961 | |
2962 static if (false) { | |
2963 if (func.isSynchronized()) | |
2964 { | |
2965 if (cd) | |
2966 { | |
2967 elem *esync; | |
2968 if (func.isStatic()) | |
2969 { // monitor is in ClassInfo | |
2970 esync = el_ptr(cd.toSymbol()); | |
2971 } | |
2972 else | |
2973 { // 'this' is the monitor | |
2974 esync = el_var(sthis); | |
2975 } | |
2976 | |
2977 if (func.isStatic() || sbody.usesEH() || | |
2978 !(config.flags2 & CFG2.CFG2seh)) | |
2979 { // BUG: what if frequire or fensure uses EH? | |
2980 | |
2981 sbody = new SynchronizedStatement(func.loc, esync, sbody); | |
2982 } | |
2983 else | |
2984 { | |
2985 version (TARGET_WINDOS) { | |
2986 if (config.flags2 & CFG2.CFG2seh) | |
2987 { | |
2988 /* The "jmonitor" uses an optimized exception handling frame | |
2989 * which is a little shorter than the more general EH frame. | |
2990 * It isn't strictly necessary. | |
2991 */ | |
2992 s.Sfunc.Fflags3 |= Fjmonitor; | |
2993 } | |
2994 } | |
2995 el_free(esync); | |
2996 } | |
2997 } | |
2998 else | |
2999 { | |
3000 error("synchronized function %s must be a member of a class", func.toChars()); | |
3001 } | |
3002 } | |
3003 } else version (TARGET_WINDOS) { | |
3004 if (func.isSynchronized() && cd && config.flags2 & CFG2.CFG2seh && | |
3005 !func.isStatic() && !sbody.usesEH()) | |
3006 { | |
3007 /* The "jmonitor" hack uses an optimized exception handling frame | |
3008 * which is a little shorter than the more general EH frame. | |
3009 */ | |
3010 s.Sfunc.Fflags3 |= F3.Fjmonitor; | |
3011 } | |
3012 } | |
3013 | |
3014 sbody.toIR(&irs); | |
3015 bx.curblock.BC = BC.BCret; | |
3016 | |
3017 f.Fstartblock = bx.startblock; | |
3018 // einit = el_combine(einit,bx.init); | |
3019 | |
3020 if (isCtorDeclaration()) | |
3021 { | |
3022 assert(sthis); | |
3023 for (b = f.Fstartblock; b; b = b.Bnext) | |
3024 { | |
3025 if (b.BC == BC.BCret) | |
3026 { | |
3027 b.BC = BC.BCretexp; | |
3028 b.Belem = el_combine(b.Belem, el_var(sthis)); | |
3029 } | |
3030 } | |
3031 } | |
3032 } | |
3033 | |
3034 // If static constructor | |
3035 if (isStaticConstructor()) | |
3036 { | |
3037 elem* e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s)); | |
3038 ector = el_combine(ector, e); | |
3039 } | |
3040 | |
3041 // If static destructor | |
3042 if (isStaticDestructor()) | |
3043 { | |
3044 elem* e; | |
3045 | |
3046 version (STATICCTOR) { | |
3047 e = el_bin(OPER.OPcall, TYM.TYvoid, el_var(rtlsym[RTLSYM.RTLSYM_FATEXIT]), el_ptr(s)); | |
3048 ector = el_combine(ector, e); | |
3049 dtorcount++; | |
3050 } else { | |
3051 StaticDtorDeclaration f2 = isStaticDtorDeclaration(); | |
3052 assert(f2); | |
3053 if (f2.vgate) | |
3054 { | |
3055 /* Increment destructor's vgate at construction time | |
3056 */ | |
3057 ectorgates.push(cast(void*)f2); | |
3058 } | |
3059 | |
3060 e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s)); | |
3061 edtor = el_combine(e, edtor); | |
3062 } | |
3063 } | |
3064 | |
3065 // If unit test | |
3066 if (isUnitTestDeclaration()) | |
3067 { | |
3068 elem* e = el_una(OPER.OPucall, TYM.TYvoid, el_var(s)); | |
3069 etest = el_combine(etest, e); | |
3070 } | |
3071 | |
3072 if (global.errors) | |
3073 return; | |
3074 | |
3075 writefunc(s); | |
3076 | |
3077 if (isExport()) { | |
3078 obj_export(s, Poffset); | |
3079 } | |
3080 | |
3081 for (i = 0; i < irs.deferToObj.dim; i++) | |
3082 { | |
3083 Dsymbol ss = cast(Dsymbol)irs.deferToObj.data[i]; | |
3084 ss.toObjFile(0); | |
3085 } | |
3086 | |
3087 version (XXX) { ///TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS | |
3088 // A hack to get a pointer to this function put in the .dtors segment | |
3089 if (ident && ident.toChars() == "_STD") { | |
3090 obj_staticdtor(s); | |
3091 } | |
3092 } | |
3093 version (DMDV2) { | |
3094 if (irs.startaddress) | |
3095 { | |
3096 writef("Setting start address\n"); | |
3097 obj_startaddress(irs.startaddress); | |
3098 } | |
3099 } | |
3100 } | |
3101 | |
3102 int cvMember(ubyte* p) | |
3103 { | |
3104 assert(false); | |
3105 } | |
3106 | |
3107 /************************************* | |
3108 * Closures are implemented by taking the local variables that | |
3109 * need to survive the scope of the function, and copying them | |
3110 * into a gc allocated chuck of memory. That chunk, called the | |
3111 * closure here, is inserted into the linked list of stack | |
3112 * frames instead of the usual stack frame. | |
3113 * | |
3114 * buildClosure() inserts code just after the function prolog | |
3115 * is complete. It allocates memory for the closure, allocates | |
3116 * a local variable (sclosure) to point to it, inserts into it | |
3117 * the link to the enclosing frame, and copies into it the parameters | |
3118 * that are referred to in nested functions. | |
3119 * In VarExp.toElem and SymOffExp.toElem, when referring to a | |
3120 * variable that is in a closure, takes the offset from sclosure rather | |
3121 * than from the frame pointer. | |
3122 * | |
3123 * getEthis() and NewExp.toElem need to use sclosure, if set, rather | |
3124 * than the current frame pointer. | |
3125 */ | |
3126 void buildClosure(IRState* irs) | |
3127 { | |
3128 if (needsClosure()) | |
3129 { | |
3130 // Generate closure on the heap | |
3131 // BUG: doesn't capture variadic arguments passed to this function | |
3132 | |
3133 version (DMDV2) { | |
3134 /* BUG: doesn't handle destructors for the local variables. | |
3135 * The way to do it is to make the closure variables the fields | |
3136 * of a class object: | |
3137 * class Closure | |
3138 * { vtbl[] | |
3139 * monitor | |
3140 * ptr to destructor | |
3141 * sthis | |
3142 * ... closure variables ... | |
3143 * ~this() { call destructor } | |
3144 * } | |
3145 */ | |
3146 } | |
3147 //printf("FuncDeclaration.buildClosure()\n"); | |
3148 Symbol* sclosure; | |
3149 sclosure = symbol_name("__closptr".ptr, SC.SCauto, Type.tvoidptr.toCtype()); | |
3150 sclosure.Sflags |= SFL.SFLtrue | SFL.SFLfree; | |
3151 symbol_add(sclosure); | |
3152 irs.sclosure = sclosure; | |
3153 | |
3154 uint offset = PTRSIZE; // leave room for previous sthis | |
3155 for (int i = 0; i < closureVars.dim; i++) | |
3156 { | |
3157 VarDeclaration v = cast(VarDeclaration)closureVars.data[i]; | |
3158 assert(v.isVarDeclaration()); | |
3159 | |
3160 version (DMDV2) { | |
3161 if (v.needsAutoDtor()) | |
3162 v.error("has scoped destruction, cannot build closure"); | |
3163 } | |
3164 /* Align and allocate space for v in the closure | |
3165 * just like AggregateDeclaration.addField() does. | |
3166 */ | |
3167 uint memsize; | |
3168 uint memalignsize; | |
3169 uint xalign; | |
3170 /// version (DMDV2) { | |
3171 if (v.storage_class & STC.STClazy) | |
3172 { | |
3173 /* Lazy variables are really delegates, | |
3174 * so give same answers that TypeDelegate would | |
3175 */ | |
3176 memsize = PTRSIZE * 2; | |
3177 memalignsize = memsize; | |
3178 xalign = global.structalign; | |
3179 } | |
3180 else | |
3181 /// } | |
3182 { | |
3183 memsize = cast(uint)v.type.size(); | |
3184 memalignsize = v.type.alignsize(); | |
3185 xalign = v.type.memalign(global.structalign); | |
3186 } | |
3187 AggregateDeclaration.alignmember(xalign, memalignsize, &offset); | |
3188 v.offset = offset; | |
3189 offset += memsize; | |
3190 | |
3191 /* Can't do nrvo if the variable is put in a closure, since | |
3192 * what the shidden points to may no longer exist. | |
3193 */ | |
3194 if (nrvo_can && nrvo_var == v) | |
3195 { | |
3196 nrvo_can = 0; | |
3197 } | |
3198 } | |
3199 // offset is now the size of the closure | |
3200 | |
3201 // Allocate memory for the closure | |
3202 elem* e; | |
3203 e = el_long(TYM.TYint, offset); | |
3204 e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[RTLSYM.RTLSYM_ALLOCMEMORY]), e); | |
3205 | |
3206 // Assign block of memory to sclosure | |
3207 // sclosure = allocmemory(sz); | |
3208 e = el_bin(OPER.OPeq, TYM.TYvoid, el_var(sclosure), e); | |
3209 | |
3210 // Set the first element to sthis | |
3211 // *(sclosure + 0) = sthis; | |
3212 elem* ethis; | |
3213 if (irs.sthis) | |
3214 ethis = el_var(irs.sthis); | |
3215 else | |
3216 ethis = el_long(TYM.TYnptr, 0); | |
3217 elem *ex = el_una(OPER.OPind, TYM.TYnptr, el_var(sclosure)); | |
3218 ex = el_bin(OPER.OPeq, TYM.TYnptr, ex, ethis); | |
3219 e = el_combine(e, ex); | |
3220 | |
3221 // Copy function parameters into closure | |
3222 for (int i = 0; i < closureVars.dim; i++) | |
3223 { VarDeclaration v = cast(VarDeclaration)closureVars.data[i]; | |
3224 | |
3225 if (!v.isParameter()) | |
3226 continue; | |
3227 TYM tym = v.type.totym(); | |
3228 if (v.type.toBasetype().ty == TY.Tsarray || v.isOut() || v.isRef()) | |
3229 tym = TYM.TYnptr; // reference parameters are just pointers | |
3230 /// version (DMDV2) { | |
3231 else if (v.storage_class & STC.STClazy) | |
3232 tym = TYM.TYdelegate; | |
3233 /// } | |
3234 ex = el_bin(OPER.OPadd, TYM.TYnptr, el_var(sclosure), el_long(TYM.TYint, v.offset)); | |
3235 ex = el_una(OPER.OPind, tym, ex); | |
3236 if (ex.Ety == TYM.TYstruct) | |
3237 { | |
3238 ex.Enumbytes = cast(uint)v.type.size(); | |
3239 ex = el_bin(OPER.OPstreq, tym, ex, el_var(v.toSymbol())); | |
3240 ex.Enumbytes = cast(uint)v.type.size(); | |
3241 } | |
3242 else | |
3243 { | |
3244 ex = el_bin(OPER.OPeq, tym, ex, el_var(v.toSymbol())); | |
3245 } | |
3246 | |
3247 e = el_combine(e, ex); | |
3248 } | |
3249 | |
3250 block_appendexp(irs.blx.curblock, e); | |
3251 } | |
3252 } | |
3253 | |
3254 FuncDeclaration isFuncDeclaration() { return this; } | |
14
2cc604139636
Implemented Linux support for ddmd. Some parts are a bit hacky to just "get it working", that said, druntime and phobos compile, and unittests pass.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
3255 } |