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