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