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