Mercurial > projects > ldc
annotate dmd/func.c @ 650:aa6a0b7968f7
Added test case for bug #100
Removed dubious check for not emitting static private global in other modules without access. This should be handled properly somewhere else, it's causing unresolved global errors for stuff that should work (in MiniD)
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sun, 05 Oct 2008 17:28:15 +0200 |
parents | 49466efd4fba |
children | 50383e476c7e |
rev | line source |
---|---|
159 | 1 |
2 // Compiler implementation of the D programming language | |
3 // Copyright (c) 1999-2008 by Digital Mars | |
4 // All Rights Reserved | |
5 // written by Walter Bright | |
6 // http://www.digitalmars.com | |
7 // License for redistribution is by either the Artistic License | |
8 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
9 // See the included readme.txt for details. | |
10 | |
11 #include <stdio.h> | |
12 #include <assert.h> | |
13 | |
14 #include "mars.h" | |
15 #include "init.h" | |
16 #include "declaration.h" | |
17 #include "attrib.h" | |
18 #include "expression.h" | |
19 #include "scope.h" | |
20 #include "mtype.h" | |
21 #include "aggregate.h" | |
22 #include "identifier.h" | |
23 #include "id.h" | |
24 #include "module.h" | |
25 #include "statement.h" | |
26 #include "template.h" | |
27 #include "hdrgen.h" | |
28 | |
29 #ifdef IN_GCC | |
30 #include "d-dmd-gcc.h" | |
31 #endif | |
32 | |
33 /********************************* FuncDeclaration ****************************/ | |
34 | |
35 FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) | |
36 : Declaration(id) | |
37 { | |
38 //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); | |
39 this->storage_class = storage_class; | |
40 this->type = type; | |
41 this->loc = loc; | |
42 this->endloc = endloc; | |
43 fthrows = NULL; | |
44 frequire = NULL; | |
45 outId = NULL; | |
46 vresult = NULL; | |
47 returnLabel = NULL; | |
48 fensure = NULL; | |
49 fbody = NULL; | |
50 localsymtab = NULL; | |
51 vthis = NULL; | |
52 v_arguments = NULL; | |
53 #if IN_GCC | |
54 v_argptr = NULL; | |
55 #endif | |
56 parameters = NULL; | |
57 labtab = NULL; | |
58 overnext = NULL; | |
59 vtblIndex = -1; | |
60 hasReturnExp = 0; | |
61 naked = 0; | |
62 inlineStatus = ILSuninitialized; | |
63 inlineNest = 0; | |
64 inlineAsm = 0; | |
65 cantInterpret = 0; | |
66 semanticRun = 0; | |
67 nestedFrameRef = 0; | |
68 fes = NULL; | |
69 introducing = 0; | |
70 tintro = NULL; | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
71 /* The type given for "infer the return type" is a TypeFunction with |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
72 * NULL for the return type. |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
73 */ |
159 | 74 inferRetType = (type && type->nextOf() == NULL); |
75 scope = NULL; | |
76 hasReturnExp = 0; | |
77 nrvo_can = 1; | |
78 nrvo_var = NULL; | |
79 shidden = NULL; | |
80 } | |
81 | |
82 Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) | |
83 { | |
84 FuncDeclaration *f; | |
85 | |
86 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); | |
87 if (s) | |
88 f = (FuncDeclaration *)s; | |
89 else | |
90 f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); | |
91 f->outId = outId; | |
92 f->frequire = frequire ? frequire->syntaxCopy() : NULL; | |
93 f->fensure = fensure ? fensure->syntaxCopy() : NULL; | |
94 f->fbody = fbody ? fbody->syntaxCopy() : NULL; | |
95 assert(!fthrows); // deprecated | |
443
44f08170f4ef
Removed tango from the repository and instead added a runtime dir with the files needed to patch and build tango from svn.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
378
diff
changeset
|
96 |
44f08170f4ef
Removed tango from the repository and instead added a runtime dir with the files needed to patch and build tango from svn.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
378
diff
changeset
|
97 // LLVMDC |
44f08170f4ef
Removed tango from the repository and instead added a runtime dir with the files needed to patch and build tango from svn.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
378
diff
changeset
|
98 f->intrinsicName = intrinsicName; |
44f08170f4ef
Removed tango from the repository and instead added a runtime dir with the files needed to patch and build tango from svn.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
378
diff
changeset
|
99 |
159 | 100 return f; |
101 } | |
102 | |
103 | |
104 // Do the semantic analysis on the external interface to the function. | |
105 | |
106 void FuncDeclaration::semantic(Scope *sc) | |
107 { TypeFunction *f; | |
108 StructDeclaration *sd; | |
109 ClassDeclaration *cd; | |
110 InterfaceDeclaration *id; | |
336 | 111 Dsymbol *pd; |
159 | 112 |
113 #if 0 | |
114 printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); | |
115 if (isFuncLiteralDeclaration()) | |
116 printf("\tFuncLiteralDeclaration()\n"); | |
117 printf("sc->parent = %s\n", sc->parent->toChars()); | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
118 printf("type: %p, %s\n", type, type->toChars()); |
159 | 119 #endif |
120 | |
121 if (type->nextOf()) | |
122 type = type->semantic(loc, sc); | |
123 //type->print(); | |
124 if (type->ty != Tfunction) | |
125 { | |
126 error("%s must be a function", toChars()); | |
127 return; | |
128 } | |
129 f = (TypeFunction *)(type); | |
130 size_t nparams = Argument::dim(f->parameters); | |
131 | |
132 linkage = sc->linkage; | |
133 // if (!parent) | |
134 { | |
135 //parent = sc->scopesym; | |
136 parent = sc->parent; | |
137 } | |
138 protection = sc->protection; | |
139 storage_class |= sc->stc; | |
140 //printf("function storage_class = x%x\n", storage_class); | |
141 Dsymbol *parent = toParent(); | |
142 | |
143 if (isConst() || isAuto() || isScope()) | |
144 error("functions cannot be const or auto"); | |
145 | |
146 if (isAbstract() && !isVirtual()) | |
147 error("non-virtual functions cannot be abstract"); | |
148 | |
149 if (isAbstract() && isFinal()) | |
150 error("cannot be both final and abstract"); | |
151 #if 0 | |
152 if (isAbstract() && fbody) | |
153 error("abstract functions cannot have bodies"); | |
154 #endif | |
155 | |
156 #if 0 | |
157 if (isStaticConstructor() || isStaticDestructor()) | |
158 { | |
159 if (!isStatic() || type->nextOf()->ty != Tvoid) | |
160 error("static constructors / destructors must be static void"); | |
161 if (f->arguments && f->arguments->dim) | |
162 error("static constructors / destructors must have empty parameter list"); | |
163 // BUG: check for invalid storage classes | |
164 } | |
165 #endif | |
166 | |
167 #ifdef IN_GCC | |
168 AggregateDeclaration *ad; | |
169 | |
170 ad = parent->isAggregateDeclaration(); | |
171 if (ad) | |
172 ad->methods.push(this); | |
173 #endif | |
174 sd = parent->isStructDeclaration(); | |
175 if (sd) | |
176 { | |
177 // Verify no constructors, destructors, etc. | |
178 if (isCtorDeclaration() || | |
179 isDtorDeclaration() | |
180 //|| isInvariantDeclaration() | |
181 //|| isUnitTestDeclaration() | |
182 ) | |
183 { | |
184 error("special member functions not allowed for %ss", sd->kind()); | |
185 } | |
186 | |
187 #if 0 | |
188 if (!sd->inv) | |
189 sd->inv = isInvariantDeclaration(); | |
190 | |
191 if (!sd->aggNew) | |
192 sd->aggNew = isNewDeclaration(); | |
193 | |
194 if (isDelete()) | |
195 { | |
196 if (sd->aggDelete) | |
197 error("multiple delete's for struct %s", sd->toChars()); | |
198 sd->aggDelete = (DeleteDeclaration *)(this); | |
199 } | |
200 #endif | |
201 } | |
202 | |
203 id = parent->isInterfaceDeclaration(); | |
204 if (id) | |
205 { | |
206 storage_class |= STCabstract; | |
207 | |
208 if (isCtorDeclaration() || | |
209 isDtorDeclaration() || | |
210 isInvariantDeclaration() || | |
211 isUnitTestDeclaration() || isNewDeclaration() || isDelete()) | |
212 error("special function not allowed in interface %s", id->toChars()); | |
213 if (fbody) | |
214 error("function body is not abstract in interface %s", id->toChars()); | |
215 } | |
216 | |
336 | 217 /* Template member functions aren't virtual: |
218 * interface TestInterface { void tpl(T)(); } | |
219 * and so won't work in interfaces | |
220 */ | |
221 if ((pd = toParent()) != NULL && | |
222 pd->isTemplateInstance() && | |
223 (pd = toParent2()) != NULL && | |
224 (id = pd->isInterfaceDeclaration()) != NULL) | |
225 { | |
226 error("template member function not allowed in interface %s", id->toChars()); | |
227 } | |
228 | |
159 | 229 cd = parent->isClassDeclaration(); |
230 if (cd) | |
231 { int vi; | |
232 CtorDeclaration *ctor; | |
233 DtorDeclaration *dtor; | |
234 InvariantDeclaration *inv; | |
235 | |
236 if (isCtorDeclaration()) | |
237 { | |
238 // ctor = (CtorDeclaration *)this; | |
239 // if (!cd->ctor) | |
240 // cd->ctor = ctor; | |
241 return; | |
242 } | |
243 | |
244 #if 0 | |
245 dtor = isDtorDeclaration(); | |
246 if (dtor) | |
247 { | |
248 if (cd->dtor) | |
249 error("multiple destructors for class %s", cd->toChars()); | |
250 cd->dtor = dtor; | |
251 } | |
252 | |
253 inv = isInvariantDeclaration(); | |
254 if (inv) | |
255 { | |
256 cd->inv = inv; | |
257 } | |
258 | |
259 if (isNewDeclaration()) | |
260 { | |
261 if (!cd->aggNew) | |
262 cd->aggNew = (NewDeclaration *)(this); | |
263 } | |
264 | |
265 if (isDelete()) | |
266 { | |
267 if (cd->aggDelete) | |
268 error("multiple delete's for class %s", cd->toChars()); | |
269 cd->aggDelete = (DeleteDeclaration *)(this); | |
270 } | |
271 #endif | |
272 | |
273 if (storage_class & STCabstract) | |
274 cd->isabstract = 1; | |
275 | |
276 // if static function, do not put in vtbl[] | |
277 if (!isVirtual()) | |
278 { | |
279 //printf("\tnot virtual\n"); | |
280 goto Ldone; | |
281 } | |
282 | |
283 // Find index of existing function in vtbl[] to override | |
284 vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0); | |
285 switch (vi) | |
286 { | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
287 case -1: |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
288 /* Didn't find one, so |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
289 * This is an 'introducing' function which gets a new |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
290 * slot in the vtbl[]. |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
291 */ |
159 | 292 |
293 // Verify this doesn't override previous final function | |
294 if (cd->baseClass) | |
295 { Dsymbol *s = cd->baseClass->search(loc, ident, 0); | |
296 if (s) | |
297 { | |
298 FuncDeclaration *f = s->isFuncDeclaration(); | |
299 f = f->overloadExactMatch(type); | |
300 if (f && f->isFinal() && f->prot() != PROTprivate) | |
301 error("cannot override final function %s", f->toPrettyChars()); | |
302 } | |
303 } | |
304 | |
305 if (isFinal()) | |
306 { | |
307 cd->vtblFinal.push(this); | |
308 } | |
309 else | |
310 { | |
311 // Append to end of vtbl[] | |
312 //printf("\tintroducing function\n"); | |
313 introducing = 1; | |
314 vi = cd->vtbl.dim; | |
315 cd->vtbl.push(this); | |
316 vtblIndex = vi; | |
317 } | |
318 break; | |
319 | |
320 case -2: // can't determine because of fwd refs | |
321 cd->sizeok = 2; // can't finish due to forward reference | |
322 return; | |
323 | |
324 default: | |
325 { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi]; | |
326 // This function is covariant with fdv | |
327 if (fdv->isFinal()) | |
328 error("cannot override final function %s", fdv->toPrettyChars()); | |
329 | |
336 | 330 #if DMDV2 |
159 | 331 if (!isOverride() && global.params.warnings) |
215
a58d8f4b84df
[svn r231] Changed: warnings are no longer treated as an error.
lindquist
parents:
162
diff
changeset
|
332 warning("%s: overrides base class function %s, but is not marked with 'override'", locToChars() fdv->toPrettyChars()); |
159 | 333 #endif |
334 | |
335 if (fdv->toParent() == parent) | |
336 { | |
337 // If both are mixins, then error. | |
338 // If either is not, the one that is not overrides | |
339 // the other. | |
340 if (fdv->parent->isClassDeclaration()) | |
341 break; | |
342 if (!this->parent->isClassDeclaration() | |
343 #if !BREAKABI | |
344 && !isDtorDeclaration() | |
345 #endif | |
336 | 346 #if DMDV2 |
159 | 347 && !isPostBlitDeclaration() |
348 #endif | |
349 ) | |
350 error("multiple overrides of same function"); | |
351 } | |
352 cd->vtbl.data[vi] = (void *)this; | |
353 vtblIndex = vi; | |
354 | |
355 /* This works by whenever this function is called, | |
356 * it actually returns tintro, which gets dynamically | |
357 * cast to type. But we know that tintro is a base | |
358 * of type, so we could optimize it by not doing a | |
359 * dynamic cast, but just subtracting the isBaseOf() | |
360 * offset if the value is != null. | |
361 */ | |
362 | |
363 if (fdv->tintro) | |
364 tintro = fdv->tintro; | |
365 else if (!type->equals(fdv->type)) | |
366 { | |
367 /* Only need to have a tintro if the vptr | |
368 * offsets differ | |
369 */ | |
370 int offset; | |
371 if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) | |
372 { | |
373 tintro = fdv->type; | |
374 } | |
375 } | |
376 break; | |
377 } | |
378 } | |
379 | |
380 /* Go through all the interface bases. | |
381 * If this function is covariant with any members of those interface | |
382 * functions, set the tintro. | |
383 */ | |
384 for (int i = 0; i < cd->interfaces_dim; i++) | |
385 { | |
386 #if 1 | |
387 BaseClass *b = cd->interfaces[i]; | |
388 vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); | |
389 switch (vi) | |
390 { | |
391 case -1: | |
392 break; | |
393 | |
394 case -2: | |
395 cd->sizeok = 2; // can't finish due to forward reference | |
396 return; | |
397 | |
398 default: | |
399 { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; | |
400 Type *ti = NULL; | |
401 | |
402 if (fdv->tintro) | |
403 ti = fdv->tintro; | |
404 else if (!type->equals(fdv->type)) | |
405 { | |
406 /* Only need to have a tintro if the vptr | |
407 * offsets differ | |
408 */ | |
409 int offset; | |
410 if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) | |
411 { | |
412 ti = fdv->type; | |
413 #if 0 | |
414 if (offset) | |
415 ti = fdv->type; | |
416 else if (type->nextOf()->ty == Tclass) | |
417 { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; | |
418 if (cdn && cdn->sizeok != 1) | |
419 ti = fdv->type; | |
420 } | |
421 #endif | |
422 } | |
423 } | |
424 if (ti) | |
425 { | |
426 if (tintro && !tintro->equals(ti)) | |
427 { | |
428 error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); | |
429 } | |
430 tintro = ti; | |
431 } | |
432 goto L2; | |
433 } | |
434 } | |
435 #else | |
436 BaseClass *b = cd->interfaces[i]; | |
437 for (vi = 0; vi < b->base->vtbl.dim; vi++) | |
438 { | |
439 Dsymbol *s = (Dsymbol *)b->base->vtbl.data[vi]; | |
440 //printf("interface %d vtbl[%d] %p %s\n", i, vi, s, s->toChars()); | |
441 FuncDeclaration *fdv = s->isFuncDeclaration(); | |
442 if (fdv && fdv->ident == ident) | |
443 { | |
444 int cov = type->covariant(fdv->type); | |
445 //printf("\tcov = %d\n", cov); | |
446 if (cov == 2) | |
447 { | |
448 //type->print(); | |
449 //fdv->type->print(); | |
450 //printf("%s %s\n", type->deco, fdv->type->deco); | |
451 error("of type %s overrides but is not covariant with %s of type %s", | |
452 type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); | |
453 } | |
454 if (cov == 1) | |
455 { Type *ti = NULL; | |
456 | |
457 if (fdv->tintro) | |
458 ti = fdv->tintro; | |
459 else if (!type->equals(fdv->type)) | |
460 { | |
461 /* Only need to have a tintro if the vptr | |
462 * offsets differ | |
463 */ | |
464 int offset; | |
465 if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) | |
466 { | |
467 ti = fdv->type; | |
468 #if 0 | |
469 if (offset) | |
470 ti = fdv->type; | |
471 else if (type->nextOf()->ty == Tclass) | |
472 { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; | |
473 if (cdn && cdn->sizeok != 1) | |
474 ti = fdv->type; | |
475 } | |
476 #endif | |
477 } | |
478 } | |
479 if (ti) | |
480 { | |
481 if (tintro && !tintro->equals(ti)) | |
482 { | |
483 error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); | |
484 } | |
485 tintro = ti; | |
486 } | |
487 goto L2; | |
488 } | |
489 if (cov == 3) | |
490 { | |
491 cd->sizeok = 2; // can't finish due to forward reference | |
492 return; | |
493 } | |
494 } | |
495 } | |
496 #endif | |
497 } | |
498 | |
499 if (introducing && isOverride()) | |
500 { | |
501 error("does not override any function"); | |
502 } | |
503 | |
504 L2: ; | |
505 } | |
506 else if (isOverride() && !parent->isTemplateInstance()) | |
507 error("override only applies to class member functions"); | |
508 | |
509 /* Do not allow template instances to add virtual functions | |
510 * to a class. | |
511 */ | |
512 if (isVirtual()) | |
513 { | |
514 TemplateInstance *ti = parent->isTemplateInstance(); | |
515 if (ti) | |
516 { | |
517 // Take care of nested templates | |
518 while (1) | |
519 { | |
520 TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); | |
521 if (!ti2) | |
522 break; | |
523 ti = ti2; | |
524 } | |
525 | |
526 // If it's a member template | |
527 ClassDeclaration *cd = ti->tempdecl->isClassMember(); | |
528 if (cd) | |
529 { | |
530 error("cannot use template to add virtual function to class '%s'", cd->toChars()); | |
531 } | |
532 } | |
533 } | |
534 | |
535 if (isMain()) | |
536 { | |
537 // Check parameters to see if they are either () or (char[][] args) | |
538 switch (nparams) | |
539 { | |
540 case 0: | |
541 break; | |
542 | |
543 case 1: | |
544 { | |
545 Argument *arg0 = Argument::getNth(f->parameters, 0); | |
546 if (arg0->type->ty != Tarray || | |
547 arg0->type->nextOf()->ty != Tarray || | |
548 arg0->type->nextOf()->nextOf()->ty != Tchar || | |
549 arg0->storageClass & (STCout | STCref | STClazy)) | |
550 goto Lmainerr; | |
551 break; | |
552 } | |
553 | |
554 default: | |
555 goto Lmainerr; | |
556 } | |
557 | |
558 if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) | |
559 error("must return int or void, not %s", f->nextOf()->toChars()); | |
560 if (f->varargs) | |
561 { | |
562 Lmainerr: | |
563 error("parameters must be main() or main(char[][] args)"); | |
564 } | |
565 } | |
566 | |
567 if (ident == Id::assign && (sd || cd)) | |
568 { // Disallow identity assignment operator. | |
569 | |
570 // opAssign(...) | |
571 if (nparams == 0) | |
572 { if (f->varargs == 1) | |
573 goto Lassignerr; | |
574 } | |
575 else | |
576 { | |
577 Argument *arg0 = Argument::getNth(f->parameters, 0); | |
578 Type *t0 = arg0->type->toBasetype(); | |
579 Type *tb = sd ? sd->type : cd->type; | |
580 if (arg0->type->implicitConvTo(tb) || | |
581 (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) | |
582 ) | |
583 { | |
584 if (nparams == 1) | |
585 goto Lassignerr; | |
586 Argument *arg1 = Argument::getNth(f->parameters, 1); | |
587 if (arg1->defaultArg) | |
588 goto Lassignerr; | |
589 } | |
590 } | |
591 } | |
592 | |
593 Ldone: | |
594 /* Save scope for possible later use (if we need the | |
595 * function internals) | |
596 */ | |
597 scope = new Scope(*sc); | |
598 scope->setNoFree(); | |
599 return; | |
600 | |
601 Lassignerr: | |
602 error("identity assignment operator overload is illegal"); | |
603 } | |
604 | |
605 void FuncDeclaration::semantic2(Scope *sc) | |
606 { | |
607 } | |
608 | |
609 // Do the semantic analysis on the internals of the function. | |
610 | |
611 void FuncDeclaration::semantic3(Scope *sc) | |
612 { TypeFunction *f; | |
613 AggregateDeclaration *ad; | |
614 VarDeclaration *argptr = NULL; | |
615 VarDeclaration *_arguments = NULL; | |
616 | |
617 if (!parent) | |
618 { | |
619 if (global.errors) | |
620 return; | |
621 //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); | |
622 assert(0); | |
623 } | |
624 //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); | |
625 //fflush(stdout); | |
626 //{ static int x; if (++x == 2) *(char*)0=0; } | |
627 //printf("\tlinkage = %d\n", sc->linkage); | |
628 | |
629 //printf(" sc->incontract = %d\n", sc->incontract); | |
630 if (semanticRun) | |
631 return; | |
632 semanticRun = 1; | |
633 | |
634 if (!type || type->ty != Tfunction) | |
635 return; | |
636 f = (TypeFunction *)(type); | |
637 size_t nparams = Argument::dim(f->parameters); | |
638 | |
639 // Check the 'throws' clause | |
640 if (fthrows) | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
641 { |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
642 for (int i = 0; i < fthrows->dim; i++) |
159 | 643 { |
644 Type *t = (Type *)fthrows->data[i]; | |
645 | |
646 t = t->semantic(loc, sc); | |
647 if (!t->isClassHandle()) | |
648 error("can only throw classes, not %s", t->toChars()); | |
649 } | |
650 } | |
651 | |
652 if (fbody || frequire) | |
653 { | |
654 /* Symbol table into which we place parameters and nested functions, | |
655 * solely to diagnose name collisions. | |
656 */ | |
657 localsymtab = new DsymbolTable(); | |
658 | |
659 // Establish function scope | |
660 ScopeDsymbol *ss = new ScopeDsymbol(); | |
661 ss->parent = sc->scopesym; | |
662 Scope *sc2 = sc->push(ss); | |
663 sc2->func = this; | |
664 sc2->parent = this; | |
665 sc2->callSuper = 0; | |
666 sc2->sbreak = NULL; | |
667 sc2->scontinue = NULL; | |
668 sc2->sw = NULL; | |
669 sc2->fes = fes; | |
670 sc2->linkage = LINKd; | |
671 sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCfinal); | |
672 sc2->protection = PROTpublic; | |
673 sc2->explicitProtection = 0; | |
674 sc2->structalign = 8; | |
675 sc2->incontract = 0; | |
676 sc2->tf = NULL; | |
644
49466efd4fba
Don't let outer enclosing handlers propagate to nested function declarations.
Christian Kamm <kamm incasoftware de>
parents:
510
diff
changeset
|
677 sc2->tfOfTry = NULL; |
159 | 678 sc2->noctor = 0; |
679 | |
680 // Declare 'this' | |
681 ad = isThis(); | |
682 if (ad) | |
683 { VarDeclaration *v; | |
684 | |
685 if (isFuncLiteralDeclaration() && isNested()) | |
686 { | |
687 error("literals cannot be class members"); | |
688 return; | |
689 } | |
690 else | |
691 { | |
692 assert(!isNested()); // can't be both member and nested | |
693 assert(ad->handle); | |
694 v = new ThisDeclaration(ad->handle); | |
695 v->storage_class |= STCparameter | STCin; | |
696 v->semantic(sc2); | |
697 if (!sc2->insert(v)) | |
698 assert(0); | |
699 v->parent = this; | |
700 vthis = v; | |
701 } | |
702 } | |
703 else if (isNested()) | |
704 { | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
705 /* The 'this' for a nested function is the link to the |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
706 * enclosing function's stack frame. |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
707 * Note that nested functions and member functions are disjoint. |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
708 */ |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
709 VarDeclaration *v = new ThisDeclaration(Type::tvoid->pointerTo()); |
159 | 710 v->storage_class |= STCparameter | STCin; |
711 v->semantic(sc2); | |
712 if (!sc2->insert(v)) | |
713 assert(0); | |
714 v->parent = this; | |
715 vthis = v; | |
716 } | |
717 | |
718 // Declare hidden variable _arguments[] and _argptr | |
719 if (f->varargs == 1) | |
720 { Type *t; | |
721 | |
722 if (f->linkage == LINKd) | |
723 { // Declare _arguments[] | |
724 #if BREAKABI | |
725 v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); | |
726 v_arguments->storage_class = STCparameter | STCin; | |
727 v_arguments->semantic(sc2); | |
728 sc2->insert(v_arguments); | |
729 v_arguments->parent = this; | |
730 | |
731 t = Type::typeinfo->type->arrayOf(); | |
732 _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); | |
733 _arguments->semantic(sc2); | |
734 sc2->insert(_arguments); | |
735 _arguments->parent = this; | |
736 #else | |
737 t = Type::typeinfo->type->arrayOf(); | |
738 v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); | |
739 v_arguments->storage_class = STCparameter | STCin; | |
740 v_arguments->semantic(sc2); | |
741 sc2->insert(v_arguments); | |
742 v_arguments->parent = this; | |
743 #endif | |
744 } | |
745 if (f->linkage == LINKd || (parameters && parameters->dim)) | |
746 { // Declare _argptr | |
747 #if IN_GCC | |
748 t = d_gcc_builtin_va_list_d_type; | |
749 #else | |
750 t = Type::tvoid->pointerTo(); | |
751 #endif | |
752 argptr = new VarDeclaration(0, t, Id::_argptr, NULL); | |
753 argptr->semantic(sc2); | |
754 sc2->insert(argptr); | |
755 argptr->parent = this; | |
756 } | |
757 } | |
758 | |
759 // Propagate storage class from tuple parameters to their element-parameters. | |
760 if (f->parameters) | |
761 { | |
762 for (size_t i = 0; i < f->parameters->dim; i++) | |
763 { Argument *arg = (Argument *)f->parameters->data[i]; | |
764 | |
765 if (arg->type->ty == Ttuple) | |
766 { TypeTuple *t = (TypeTuple *)arg->type; | |
767 size_t dim = Argument::dim(t->arguments); | |
768 for (size_t j = 0; j < dim; j++) | |
769 { Argument *narg = Argument::getNth(t->arguments, j); | |
770 narg->storageClass = arg->storageClass; | |
771 } | |
772 } | |
773 } | |
774 } | |
775 | |
776 // Declare all the function parameters as variables | |
777 if (nparams) | |
778 { /* parameters[] has all the tuples removed, as the back end | |
779 * doesn't know about tuples | |
780 */ | |
781 parameters = new Dsymbols(); | |
782 parameters->reserve(nparams); | |
783 for (size_t i = 0; i < nparams; i++) | |
784 { | |
785 Argument *arg = Argument::getNth(f->parameters, i); | |
786 Identifier *id = arg->ident; | |
787 if (!id) | |
788 { | |
789 /* Generate identifier for un-named parameter, | |
790 * because we need it later on. | |
791 */ | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
792 arg->ident = id = Identifier::generateId("_param_", i); |
159 | 793 } |
794 VarDeclaration *v = new VarDeclaration(loc, arg->type, id, NULL); | |
795 //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); | |
796 v->storage_class |= STCparameter; | |
797 if (f->varargs == 2 && i + 1 == nparams) | |
798 v->storage_class |= STCvariadic; | |
799 v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy); | |
800 if (v->storage_class & STClazy) | |
801 v->storage_class |= STCin; | |
802 v->semantic(sc2); | |
803 if (!sc2->insert(v)) | |
804 error("parameter %s.%s is already defined", toChars(), v->toChars()); | |
805 else | |
806 parameters->push(v); | |
807 localsymtab->insert(v); | |
808 v->parent = this; | |
809 } | |
810 } | |
811 | |
812 // Declare the tuple symbols and put them in the symbol table, | |
813 // but not in parameters[]. | |
814 if (f->parameters) | |
815 { | |
816 for (size_t i = 0; i < f->parameters->dim; i++) | |
817 { Argument *arg = (Argument *)f->parameters->data[i]; | |
818 | |
819 if (!arg->ident) | |
820 continue; // never used, so ignore | |
821 if (arg->type->ty == Ttuple) | |
822 { TypeTuple *t = (TypeTuple *)arg->type; | |
823 size_t dim = Argument::dim(t->arguments); | |
824 Objects *exps = new Objects(); | |
825 exps->setDim(dim); | |
826 for (size_t j = 0; j < dim; j++) | |
827 { Argument *narg = Argument::getNth(t->arguments, j); | |
828 assert(narg->ident); | |
829 VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); | |
830 assert(v); | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
831 Expression *e = new VarExp(v->loc, v); |
159 | 832 exps->data[j] = (void *)e; |
833 } | |
834 assert(arg->ident); | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
835 TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); |
159 | 836 //printf("declaring tuple %s\n", v->toChars()); |
837 v->isexp = 1; | |
838 if (!sc2->insert(v)) | |
839 error("parameter %s.%s is already defined", toChars(), v->toChars()); | |
840 localsymtab->insert(v); | |
841 v->parent = this; | |
842 } | |
843 } | |
844 } | |
845 | |
846 /* Do the semantic analysis on the [in] preconditions and | |
847 * [out] postconditions. | |
848 */ | |
849 sc2->incontract++; | |
850 | |
851 if (frequire) | |
852 { /* frequire is composed of the [in] contracts | |
853 */ | |
854 // BUG: need to error if accessing out parameters | |
855 // BUG: need to treat parameters as const | |
856 // BUG: need to disallow returns and throws | |
857 // BUG: verify that all in and ref parameters are read | |
858 frequire = frequire->semantic(sc2); | |
859 labtab = NULL; // so body can't refer to labels | |
860 } | |
861 | |
862 if (fensure || addPostInvariant()) | |
863 { /* fensure is composed of the [out] contracts | |
864 */ | |
865 ScopeDsymbol *sym = new ScopeDsymbol(); | |
866 sym->parent = sc2->scopesym; | |
867 sc2 = sc2->push(sym); | |
868 | |
869 assert(type->nextOf()); | |
870 if (type->nextOf()->ty == Tvoid) | |
871 { | |
872 if (outId) | |
873 error("void functions have no result"); | |
874 } | |
875 else | |
876 { | |
877 if (!outId) | |
878 outId = Id::result; // provide a default | |
879 } | |
880 | |
881 if (outId) | |
882 { // Declare result variable | |
883 VarDeclaration *v; | |
884 Loc loc = this->loc; | |
885 | |
886 if (fensure) | |
887 loc = fensure->loc; | |
888 | |
889 v = new VarDeclaration(loc, type->nextOf(), outId, NULL); | |
890 v->noauto = 1; | |
891 sc2->incontract--; | |
892 v->semantic(sc2); | |
893 sc2->incontract++; | |
894 if (!sc2->insert(v)) | |
895 error("out result %s is already defined", v->toChars()); | |
896 v->parent = this; | |
897 vresult = v; | |
898 | |
899 // vresult gets initialized with the function return value | |
900 // in ReturnStatement::semantic() | |
901 } | |
902 | |
903 // BUG: need to treat parameters as const | |
904 // BUG: need to disallow returns and throws | |
905 if (fensure) | |
906 { fensure = fensure->semantic(sc2); | |
907 labtab = NULL; // so body can't refer to labels | |
908 } | |
909 | |
910 if (!global.params.useOut) | |
911 { fensure = NULL; // discard | |
912 vresult = NULL; | |
913 } | |
914 | |
915 // Postcondition invariant | |
916 if (addPostInvariant()) | |
917 { | |
918 Expression *e = NULL; | |
919 if (isCtorDeclaration()) | |
920 { | |
921 // Call invariant directly only if it exists | |
922 InvariantDeclaration *inv = ad->inv; | |
923 ClassDeclaration *cd = ad->isClassDeclaration(); | |
924 | |
925 while (!inv && cd) | |
926 { | |
927 cd = cd->baseClass; | |
928 if (!cd) | |
929 break; | |
930 inv = cd->inv; | |
931 } | |
932 if (inv) | |
933 { | |
934 e = new DsymbolExp(0, inv); | |
935 e = new CallExp(0, e); | |
936 e = e->semantic(sc2); | |
937 } | |
938 } | |
939 else | |
940 { // Call invariant virtually | |
941 ThisExp *v = new ThisExp(0); | |
942 v->type = vthis->type; | |
943 e = new AssertExp(0, v); | |
944 } | |
945 if (e) | |
946 { | |
947 ExpStatement *s = new ExpStatement(0, e); | |
948 if (fensure) | |
949 fensure = new CompoundStatement(0, s, fensure); | |
950 else | |
951 fensure = s; | |
952 } | |
953 } | |
954 | |
955 if (fensure) | |
956 { returnLabel = new LabelDsymbol(Id::returnLabel); | |
957 LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); | |
958 ls->isReturnLabel = 1; | |
959 returnLabel->statement = ls; | |
960 } | |
961 sc2 = sc2->pop(); | |
962 } | |
963 | |
964 sc2->incontract--; | |
965 | |
966 if (fbody) | |
967 { ClassDeclaration *cd = isClassMember(); | |
968 | |
969 /* If this is a class constructor | |
970 */ | |
971 if (isCtorDeclaration() && cd) | |
972 { | |
973 for (int i = 0; i < cd->fields.dim; i++) | |
974 { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; | |
975 | |
976 v->ctorinit = 0; | |
977 } | |
978 } | |
979 | |
980 if (inferRetType || f->retStyle() != RETstack) | |
981 nrvo_can = 0; | |
982 | |
983 fbody = fbody->semantic(sc2); | |
984 | |
985 if (inferRetType) | |
986 { // If no return type inferred yet, then infer a void | |
987 if (!type->nextOf()) | |
988 { | |
989 ((TypeFunction *)type)->next = Type::tvoid; | |
990 type = type->semantic(loc, sc); | |
991 } | |
992 f = (TypeFunction *)type; | |
993 } | |
994 | |
336 | 995 int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE; |
996 //int offend = fbody ? fbody->fallOffEnd() : TRUE; | |
159 | 997 |
998 if (isStaticCtorDeclaration()) | |
999 { /* It's a static constructor. Ensure that all | |
1000 * ctor consts were initialized. | |
1001 */ | |
1002 | |
1003 Dsymbol *p = toParent(); | |
1004 ScopeDsymbol *ad = p->isScopeDsymbol(); | |
1005 if (!ad) | |
1006 { | |
1007 error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); | |
1008 } | |
1009 else | |
1010 { | |
1011 for (int i = 0; i < ad->members->dim; i++) | |
1012 { Dsymbol *s = (Dsymbol *)ad->members->data[i]; | |
1013 | |
1014 s->checkCtorConstInit(); | |
1015 } | |
1016 } | |
1017 } | |
1018 | |
1019 if (isCtorDeclaration() && cd) | |
1020 { | |
1021 //printf("callSuper = x%x\n", sc2->callSuper); | |
1022 | |
1023 // Verify that all the ctorinit fields got initialized | |
1024 if (!(sc2->callSuper & CSXthis_ctor)) | |
1025 { | |
1026 for (int i = 0; i < cd->fields.dim; i++) | |
1027 { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; | |
1028 | |
1029 if (v->ctorinit == 0 && v->isCtorinit()) | |
1030 error("missing initializer for const field %s", v->toChars()); | |
1031 } | |
1032 } | |
1033 | |
1034 if (!(sc2->callSuper & CSXany_ctor) && | |
1035 cd->baseClass && cd->baseClass->ctor) | |
1036 { | |
1037 sc2->callSuper = 0; | |
1038 | |
1039 // Insert implicit super() at start of fbody | |
1040 Expression *e1 = new SuperExp(0); | |
1041 Expression *e = new CallExp(0, e1); | |
1042 | |
1043 unsigned errors = global.errors; | |
1044 global.gag++; | |
1045 e = e->semantic(sc2); | |
1046 global.gag--; | |
1047 if (errors != global.errors) | |
1048 error("no match for implicit super() call in constructor"); | |
1049 | |
1050 Statement *s = new ExpStatement(0, e); | |
1051 fbody = new CompoundStatement(0, s, fbody); | |
1052 } | |
1053 } | |
1054 else if (fes) | |
1055 { // For foreach(){} body, append a return 0; | |
1056 Expression *e = new IntegerExp(0); | |
1057 Statement *s = new ReturnStatement(0, e); | |
1058 fbody = new CompoundStatement(0, fbody, s); | |
1059 assert(!returnLabel); | |
1060 } | |
1061 else if (!hasReturnExp && type->nextOf()->ty != Tvoid) | |
1062 error("expected to return a value of type %s", type->nextOf()->toChars()); | |
1063 else if (!inlineAsm) | |
1064 { | |
1065 if (type->nextOf()->ty == Tvoid) | |
1066 { | |
1067 if (offend && isMain()) | |
1068 { // Add a return 0; statement | |
1069 Statement *s = new ReturnStatement(0, new IntegerExp(0)); | |
1070 fbody = new CompoundStatement(0, fbody, s); | |
1071 } | |
1072 } | |
1073 else | |
1074 { | |
1075 if (offend) | |
1076 { Expression *e; | |
1077 | |
1078 if (global.params.warnings) | |
215
a58d8f4b84df
[svn r231] Changed: warnings are no longer treated as an error.
lindquist
parents:
162
diff
changeset
|
1079 { warning("%s: no return at end of function", locToChars()); |
159 | 1080 } |
1081 | |
1082 if (global.params.useAssert && | |
1083 !global.params.useInline) | |
1084 { /* Add an assert(0, msg); where the missing return | |
1085 * should be. | |
1086 */ | |
1087 e = new AssertExp( | |
1088 endloc, | |
1089 new IntegerExp(0), | |
1090 new StringExp(loc, "missing return expression") | |
1091 ); | |
1092 } | |
1093 else | |
1094 e = new HaltExp(endloc); | |
1095 e = new CommaExp(0, e, type->nextOf()->defaultInit()); | |
1096 e = e->semantic(sc2); | |
1097 Statement *s = new ExpStatement(0, e); | |
1098 fbody = new CompoundStatement(0, fbody, s); | |
1099 } | |
1100 } | |
1101 } | |
1102 } | |
1103 | |
1104 { | |
1105 Statements *a = new Statements(); | |
1106 | |
1107 // Merge in initialization of 'out' parameters | |
1108 if (parameters) | |
1109 { for (size_t i = 0; i < parameters->dim; i++) | |
1110 { | |
1111 VarDeclaration *v = (VarDeclaration *)parameters->data[i]; | |
1112 if (v->storage_class & STCout) | |
1113 { | |
1114 assert(v->init); | |
1115 ExpInitializer *ie = v->init->isExpInitializer(); | |
1116 assert(ie); | |
1117 a->push(new ExpStatement(0, ie->exp)); | |
1118 } | |
1119 } | |
1120 } | |
1121 | |
1122 // we'll handle variadics ourselves | |
1123 #if !IN_LLVM | |
1124 if (argptr) | |
1125 { // Initialize _argptr to point past non-variadic arg | |
1126 #if IN_GCC | |
1127 // Handled in FuncDeclaration::toObjFile | |
1128 v_argptr = argptr; | |
1129 v_argptr->init = new VoidInitializer(loc); | |
1130 #else | |
1131 Expression *e1; | |
1132 Expression *e; | |
1133 Type *t = argptr->type; | |
1134 VarDeclaration *p; | |
1135 unsigned offset; | |
1136 | |
1137 e1 = new VarExp(0, argptr); | |
1138 if (parameters && parameters->dim) | |
1139 p = (VarDeclaration *)parameters->data[parameters->dim - 1]; | |
1140 else | |
1141 p = v_arguments; // last parameter is _arguments[] | |
1142 offset = p->type->size(); | |
1143 offset = (offset + 3) & ~3; // assume stack aligns on 4 | |
1144 e = new SymOffExp(0, p, offset); | |
1145 e = new AssignExp(0, e1, e); | |
1146 e->type = t; | |
1147 a->push(new ExpStatement(0, e)); | |
1148 #endif // IN_GCC | |
1149 } | |
1150 | |
1151 if (_arguments) | |
1152 { | |
1153 /* Advance to elements[] member of TypeInfo_Tuple with: | |
1154 * _arguments = v_arguments.elements; | |
1155 */ | |
1156 Expression *e = new VarExp(0, v_arguments); | |
1157 e = new DotIdExp(0, e, Id::elements); | |
1158 Expression *e1 = new VarExp(0, _arguments); | |
1159 e = new AssignExp(0, e1, e); | |
1160 e = e->semantic(sc); | |
1161 a->push(new ExpStatement(0, e)); | |
1162 } | |
1163 | |
1164 #endif // !IN_LLVM | |
1165 | |
1166 // Merge contracts together with body into one compound statement | |
1167 | |
1168 #ifdef _DH | |
1169 if (frequire && global.params.useIn) | |
1170 { frequire->incontract = 1; | |
1171 a->push(frequire); | |
1172 } | |
1173 #else | |
1174 if (frequire && global.params.useIn) | |
1175 a->push(frequire); | |
1176 #endif | |
1177 | |
1178 // Precondition invariant | |
1179 if (addPreInvariant()) | |
1180 { | |
1181 Expression *e = NULL; | |
1182 if (isDtorDeclaration()) | |
1183 { | |
1184 // Call invariant directly only if it exists | |
1185 InvariantDeclaration *inv = ad->inv; | |
1186 ClassDeclaration *cd = ad->isClassDeclaration(); | |
1187 | |
1188 while (!inv && cd) | |
1189 { | |
1190 cd = cd->baseClass; | |
1191 if (!cd) | |
1192 break; | |
1193 inv = cd->inv; | |
1194 } | |
1195 if (inv) | |
1196 { | |
1197 e = new DsymbolExp(0, inv); | |
1198 e = new CallExp(0, e); | |
1199 e = e->semantic(sc2); | |
1200 } | |
1201 } | |
1202 else | |
1203 { // Call invariant virtually | |
1204 ThisExp *v = new ThisExp(0); | |
1205 v->type = vthis->type; | |
1206 Expression *se = new StringExp(0, "null this"); | |
1207 se = se->semantic(sc); | |
1208 se->type = Type::tchar->arrayOf(); | |
1209 e = new AssertExp(loc, v, se); | |
1210 } | |
1211 if (e) | |
1212 { | |
1213 ExpStatement *s = new ExpStatement(0, e); | |
1214 a->push(s); | |
1215 } | |
1216 } | |
1217 | |
1218 if (fbody) | |
1219 a->push(fbody); | |
1220 | |
1221 if (fensure) | |
1222 { | |
1223 a->push(returnLabel->statement); | |
1224 | |
1225 if (type->nextOf()->ty != Tvoid) | |
1226 { | |
1227 // Create: return vresult; | |
1228 assert(vresult); | |
1229 Expression *e = new VarExp(0, vresult); | |
1230 if (tintro) | |
1231 { e = e->implicitCastTo(sc, tintro->nextOf()); | |
1232 e = e->semantic(sc); | |
1233 } | |
1234 ReturnStatement *s = new ReturnStatement(0, e); | |
1235 a->push(s); | |
1236 } | |
1237 } | |
1238 | |
1239 fbody = new CompoundStatement(0, a); | |
1240 } | |
1241 | |
1242 sc2->callSuper = 0; | |
1243 sc2->pop(); | |
1244 } | |
1245 semanticRun = 2; | |
1246 } | |
1247 | |
1248 void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
1249 { | |
1250 //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); | |
1251 | |
1252 type->toCBuffer(buf, ident, hgs); | |
1253 bodyToCBuffer(buf, hgs); | |
1254 } | |
1255 | |
1256 | |
1257 void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
1258 { | |
1259 if (fbody && | |
1260 (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) | |
1261 ) | |
1262 { buf->writenl(); | |
1263 | |
1264 // in{} | |
1265 if (frequire) | |
1266 { buf->writestring("in"); | |
1267 buf->writenl(); | |
1268 frequire->toCBuffer(buf, hgs); | |
1269 } | |
1270 | |
1271 // out{} | |
1272 if (fensure) | |
1273 { buf->writestring("out"); | |
1274 if (outId) | |
1275 { buf->writebyte('('); | |
1276 buf->writestring(outId->toChars()); | |
1277 buf->writebyte(')'); | |
1278 } | |
1279 buf->writenl(); | |
1280 fensure->toCBuffer(buf, hgs); | |
1281 } | |
1282 | |
1283 if (frequire || fensure) | |
1284 { buf->writestring("body"); | |
1285 buf->writenl(); | |
1286 } | |
1287 | |
1288 buf->writebyte('{'); | |
1289 buf->writenl(); | |
1290 fbody->toCBuffer(buf, hgs); | |
1291 buf->writebyte('}'); | |
1292 buf->writenl(); | |
1293 } | |
1294 else | |
1295 { buf->writeByte(';'); | |
1296 buf->writenl(); | |
1297 } | |
1298 } | |
1299 | |
1300 /**************************************************** | |
1301 * Determine if 'this' overrides fd. | |
1302 * Return !=0 if it does. | |
1303 */ | |
1304 | |
1305 int FuncDeclaration::overrides(FuncDeclaration *fd) | |
1306 { int result = 0; | |
1307 | |
1308 if (fd->ident == ident) | |
1309 { | |
1310 int cov = type->covariant(fd->type); | |
1311 if (cov) | |
1312 { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); | |
1313 ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); | |
1314 | |
1315 if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) | |
1316 result = 1; | |
1317 } | |
1318 } | |
1319 return result; | |
1320 } | |
1321 | |
1322 /************************************************* | |
1323 * Find index of function in vtbl[0..dim] that | |
1324 * this function overrides. | |
1325 * Returns: | |
1326 * -1 didn't find one | |
1327 * -2 can't determine because of forward references | |
1328 */ | |
1329 | |
1330 int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) | |
1331 { | |
1332 for (int vi = 0; vi < dim; vi++) | |
1333 { | |
1334 FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); | |
1335 if (fdv && fdv->ident == ident) | |
1336 { | |
1337 int cov = type->covariant(fdv->type); | |
1338 //printf("\tbaseclass cov = %d\n", cov); | |
1339 switch (cov) | |
1340 { | |
1341 case 0: // types are distinct | |
1342 break; | |
1343 | |
1344 case 1: | |
1345 return vi; | |
1346 | |
1347 case 2: | |
1348 //type->print(); | |
1349 //fdv->type->print(); | |
1350 //printf("%s %s\n", type->deco, fdv->type->deco); | |
1351 error("of type %s overrides but is not covariant with %s of type %s", | |
1352 type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); | |
1353 break; | |
1354 | |
1355 case 3: | |
1356 return -2; // forward references | |
1357 | |
1358 default: | |
1359 assert(0); | |
1360 } | |
1361 } | |
1362 } | |
1363 return -1; | |
1364 } | |
1365 | |
1366 /**************************************************** | |
1367 * Overload this FuncDeclaration with the new one f. | |
1368 * Return !=0 if successful; i.e. no conflict. | |
1369 */ | |
1370 | |
1371 int FuncDeclaration::overloadInsert(Dsymbol *s) | |
1372 { | |
1373 FuncDeclaration *f; | |
1374 AliasDeclaration *a; | |
1375 | |
1376 //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); | |
1377 a = s->isAliasDeclaration(); | |
1378 if (a) | |
1379 { | |
1380 if (overnext) | |
1381 return overnext->overloadInsert(a); | |
1382 if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) | |
1383 { | |
1384 //printf("\ta = '%s'\n", a->type->toChars()); | |
1385 return FALSE; | |
1386 } | |
1387 overnext = a; | |
1388 //printf("\ttrue: no conflict\n"); | |
1389 return TRUE; | |
1390 } | |
1391 f = s->isFuncDeclaration(); | |
1392 if (!f) | |
1393 return FALSE; | |
1394 | |
1395 if (type && f->type && // can be NULL for overloaded constructors | |
1396 f->type->covariant(type) && | |
1397 !isFuncAliasDeclaration()) | |
1398 { | |
1399 //printf("\tfalse: conflict %s\n", kind()); | |
1400 return FALSE; | |
1401 } | |
1402 | |
1403 if (overnext) | |
1404 return overnext->overloadInsert(f); | |
1405 overnext = f; | |
1406 //printf("\ttrue: no conflict\n"); | |
1407 return TRUE; | |
1408 } | |
1409 | |
1410 /******************************************** | |
1411 * Find function in overload list that exactly matches t. | |
1412 */ | |
1413 | |
1414 /*************************************************** | |
1415 * Visit each overloaded function in turn, and call | |
1416 * (*fp)(param, f) on it. | |
1417 * Exit when no more, or (*fp)(param, f) returns 1. | |
1418 * Returns: | |
1419 * 0 continue | |
1420 * 1 done | |
1421 */ | |
1422 | |
1423 int overloadApply(FuncDeclaration *fstart, | |
1424 int (*fp)(void *, FuncDeclaration *), | |
1425 void *param) | |
1426 { | |
1427 FuncDeclaration *f; | |
1428 Declaration *d; | |
1429 Declaration *next; | |
1430 | |
1431 for (d = fstart; d; d = next) | |
1432 { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); | |
1433 | |
1434 if (fa) | |
1435 { | |
1436 if (overloadApply(fa->funcalias, fp, param)) | |
1437 return 1; | |
1438 next = fa->overnext; | |
1439 } | |
1440 else | |
1441 { | |
1442 AliasDeclaration *a = d->isAliasDeclaration(); | |
1443 | |
1444 if (a) | |
1445 { | |
1446 Dsymbol *s = a->toAlias(); | |
1447 next = s->isDeclaration(); | |
1448 if (next == a) | |
1449 break; | |
1450 if (next == fstart) | |
1451 break; | |
1452 } | |
1453 else | |
1454 { | |
1455 f = d->isFuncDeclaration(); | |
1456 if (!f) | |
1457 { d->error("is aliased to a function"); | |
1458 break; // BUG: should print error message? | |
1459 } | |
1460 if ((*fp)(param, f)) | |
1461 return 1; | |
1462 | |
1463 next = f->overnext; | |
1464 } | |
1465 } | |
1466 } | |
1467 return 0; | |
1468 } | |
1469 | |
1470 /******************************************** | |
1471 * Find function in overload list that exactly matches t. | |
1472 */ | |
1473 | |
1474 struct Param1 | |
1475 { | |
1476 Type *t; // type to match | |
1477 FuncDeclaration *f; // return value | |
1478 }; | |
1479 | |
1480 int fp1(void *param, FuncDeclaration *f) | |
1481 { Param1 *p = (Param1 *)param; | |
1482 Type *t = p->t; | |
1483 | |
1484 if (t->equals(f->type)) | |
1485 { p->f = f; | |
1486 return 1; | |
1487 } | |
1488 | |
336 | 1489 #if DMDV2 |
159 | 1490 /* Allow covariant matches, if it's just a const conversion |
1491 * of the return type | |
1492 */ | |
1493 if (t->ty == Tfunction) | |
1494 { TypeFunction *tf = (TypeFunction *)f->type; | |
1495 if (tf->covariant(t) == 1 && | |
1496 tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) | |
1497 { | |
1498 p->f = f; | |
1499 return 1; | |
1500 } | |
1501 } | |
1502 #endif | |
1503 return 0; | |
1504 } | |
1505 | |
1506 FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) | |
1507 { | |
1508 Param1 p; | |
1509 p.t = t; | |
1510 p.f = NULL; | |
1511 overloadApply(this, &fp1, &p); | |
1512 return p.f; | |
1513 } | |
1514 | |
1515 #if 0 | |
1516 FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) | |
1517 { | |
1518 FuncDeclaration *f; | |
1519 Declaration *d; | |
1520 Declaration *next; | |
1521 | |
1522 for (d = this; d; d = next) | |
1523 { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); | |
1524 | |
1525 if (fa) | |
1526 { | |
1527 FuncDeclaration *f2 = fa->funcalias->overloadExactMatch(t); | |
1528 if (f2) | |
1529 return f2; | |
1530 next = fa->overnext; | |
1531 } | |
1532 else | |
1533 { | |
1534 AliasDeclaration *a = d->isAliasDeclaration(); | |
1535 | |
1536 if (a) | |
1537 { | |
1538 Dsymbol *s = a->toAlias(); | |
1539 next = s->isDeclaration(); | |
1540 if (next == a) | |
1541 break; | |
1542 } | |
1543 else | |
1544 { | |
1545 f = d->isFuncDeclaration(); | |
1546 if (!f) | |
1547 break; // BUG: should print error message? | |
1548 if (t->equals(d->type)) | |
1549 return f; | |
1550 next = f->overnext; | |
1551 } | |
1552 } | |
1553 } | |
1554 return NULL; | |
1555 } | |
1556 #endif | |
1557 | |
1558 /******************************************** | |
1559 * Decide which function matches the arguments best. | |
1560 */ | |
1561 | |
1562 struct Param2 | |
1563 { | |
1564 Match *m; | |
1565 Expressions *arguments; | |
1566 }; | |
1567 | |
1568 int fp2(void *param, FuncDeclaration *f) | |
1569 { Param2 *p = (Param2 *)param; | |
1570 Match *m = p->m; | |
1571 Expressions *arguments = p->arguments; | |
1572 MATCH match; | |
1573 | |
1574 if (f != m->lastf) // skip duplicates | |
1575 { | |
1576 m->anyf = f; | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1577 TypeFunction *tf = (TypeFunction *)f->type; |
159 | 1578 match = (MATCH) tf->callMatch(arguments); |
1579 //printf("match = %d\n", match); | |
1580 if (match != MATCHnomatch) | |
1581 { | |
1582 if (match > m->last) | |
1583 goto LfIsBetter; | |
1584 | |
1585 if (match < m->last) | |
1586 goto LlastIsBetter; | |
1587 | |
1588 /* See if one of the matches overrides the other. | |
1589 */ | |
1590 if (m->lastf->overrides(f)) | |
1591 goto LlastIsBetter; | |
1592 else if (f->overrides(m->lastf)) | |
1593 goto LfIsBetter; | |
1594 | |
1595 Lambiguous: | |
1596 m->nextf = f; | |
1597 m->count++; | |
1598 return 0; | |
1599 | |
1600 LfIsBetter: | |
1601 m->last = match; | |
1602 m->lastf = f; | |
1603 m->count = 1; | |
1604 return 0; | |
1605 | |
1606 LlastIsBetter: | |
1607 return 0; | |
1608 } | |
1609 } | |
1610 return 0; | |
1611 } | |
1612 | |
1613 | |
1614 void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments) | |
1615 { | |
1616 Param2 p; | |
1617 p.m = m; | |
1618 p.arguments = arguments; | |
1619 overloadApply(fstart, &fp2, &p); | |
1620 } | |
1621 | |
1622 #if 0 | |
1623 // Recursive helper function | |
1624 | |
1625 void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments) | |
1626 { | |
1627 MATCH match; | |
1628 Declaration *d; | |
1629 Declaration *next; | |
1630 | |
1631 for (d = fstart; d; d = next) | |
1632 { | |
1633 FuncDeclaration *f; | |
1634 FuncAliasDeclaration *fa; | |
1635 AliasDeclaration *a; | |
1636 | |
1637 fa = d->isFuncAliasDeclaration(); | |
1638 if (fa) | |
1639 { | |
1640 overloadResolveX(m, fa->funcalias, arguments); | |
1641 next = fa->overnext; | |
1642 } | |
1643 else if ((f = d->isFuncDeclaration()) != NULL) | |
1644 { | |
1645 next = f->overnext; | |
1646 if (f == m->lastf) | |
1647 continue; // skip duplicates | |
1648 else | |
1649 { | |
1650 TypeFunction *tf; | |
1651 | |
1652 m->anyf = f; | |
1653 tf = (TypeFunction *)f->type; | |
1654 match = (MATCH) tf->callMatch(arguments); | |
1655 //printf("match = %d\n", match); | |
1656 if (match != MATCHnomatch) | |
1657 { | |
1658 if (match > m->last) | |
1659 goto LfIsBetter; | |
1660 | |
1661 if (match < m->last) | |
1662 goto LlastIsBetter; | |
1663 | |
1664 /* See if one of the matches overrides the other. | |
1665 */ | |
1666 if (m->lastf->overrides(f)) | |
1667 goto LlastIsBetter; | |
1668 else if (f->overrides(m->lastf)) | |
1669 goto LfIsBetter; | |
1670 | |
1671 Lambiguous: | |
1672 m->nextf = f; | |
1673 m->count++; | |
1674 continue; | |
1675 | |
1676 LfIsBetter: | |
1677 m->last = match; | |
1678 m->lastf = f; | |
1679 m->count = 1; | |
1680 continue; | |
1681 | |
1682 LlastIsBetter: | |
1683 continue; | |
1684 } | |
1685 } | |
1686 } | |
1687 else if ((a = d->isAliasDeclaration()) != NULL) | |
1688 { | |
1689 Dsymbol *s = a->toAlias(); | |
1690 next = s->isDeclaration(); | |
1691 if (next == a) | |
1692 break; | |
1693 if (next == fstart) | |
1694 break; | |
1695 } | |
1696 else | |
1697 { d->error("is aliased to a function"); | |
1698 break; | |
1699 } | |
1700 } | |
1701 } | |
1702 #endif | |
1703 | |
1704 FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expressions *arguments) | |
1705 { | |
1706 TypeFunction *tf; | |
1707 Match m; | |
1708 | |
1709 #if 0 | |
1710 printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); | |
1711 if (arguments) | |
1712 { int i; | |
1713 | |
1714 for (i = 0; i < arguments->dim; i++) | |
1715 { Expression *arg; | |
1716 | |
1717 arg = (Expression *)arguments->data[i]; | |
1718 assert(arg->type); | |
1719 printf("\t%s: ", arg->toChars()); | |
1720 arg->type->print(); | |
1721 } | |
1722 } | |
1723 #endif | |
1724 | |
1725 memset(&m, 0, sizeof(m)); | |
1726 m.last = MATCHnomatch; | |
1727 overloadResolveX(&m, this, arguments); | |
1728 | |
1729 if (m.count == 1) // exactly one match | |
1730 { | |
1731 return m.lastf; | |
1732 } | |
1733 else | |
1734 { | |
1735 OutBuffer buf; | |
1736 | |
1737 if (arguments) | |
1738 { | |
1739 HdrGenState hgs; | |
1740 | |
1741 argExpTypesToCBuffer(&buf, arguments, &hgs); | |
1742 } | |
1743 | |
1744 if (m.last == MATCHnomatch) | |
1745 { | |
1746 tf = (TypeFunction *)type; | |
1747 | |
1748 //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); | |
1749 error(loc, "%s does not match parameter types (%s)", | |
1750 Argument::argsTypesToChars(tf->parameters, tf->varargs), | |
1751 buf.toChars()); | |
1752 return m.anyf; // as long as it's not a FuncAliasDeclaration | |
1753 } | |
1754 else | |
1755 { | |
1756 #if 1 | |
1757 TypeFunction *t1 = (TypeFunction *)m.lastf->type; | |
1758 TypeFunction *t2 = (TypeFunction *)m.nextf->type; | |
1759 | |
1760 error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", | |
1761 buf.toChars(), | |
1762 m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs), | |
1763 m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); | |
1764 #else | |
1765 error(loc, "overloads %s and %s both match argument list for %s", | |
1766 m.lastf->type->toChars(), | |
1767 m.nextf->type->toChars(), | |
1768 m.lastf->toChars()); | |
1769 #endif | |
1770 return m.lastf; | |
1771 } | |
1772 } | |
1773 } | |
1774 | |
1775 /******************************** | |
1776 * Labels are in a separate scope, one per function. | |
1777 */ | |
1778 | |
1779 LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) | |
1780 { Dsymbol *s; | |
1781 | |
1782 if (!labtab) | |
1783 labtab = new DsymbolTable(); // guess we need one | |
1784 | |
1785 s = labtab->lookup(ident); | |
1786 if (!s) | |
1787 { | |
1788 s = new LabelDsymbol(ident); | |
1789 labtab->insert(s); | |
1790 } | |
1791 return (LabelDsymbol *)s; | |
1792 } | |
336 | 1793 |
159 | 1794 /**************************************** |
1795 * If non-static member function that has a 'this' pointer, | |
1796 * return the aggregate it is a member of. | |
1797 * Otherwise, return NULL. | |
1798 */ | |
1799 | |
1800 AggregateDeclaration *FuncDeclaration::isThis() | |
1801 { AggregateDeclaration *ad; | |
1802 | |
1803 //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); | |
1804 ad = NULL; | |
1805 if ((storage_class & STCstatic) == 0) | |
1806 { | |
1807 ad = isMember2(); | |
1808 } | |
1809 //printf("-FuncDeclaration::isThis() %p\n", ad); | |
1810 return ad; | |
1811 } | |
1812 | |
1813 AggregateDeclaration *FuncDeclaration::isMember2() | |
1814 { AggregateDeclaration *ad; | |
1815 | |
1816 //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); | |
1817 ad = NULL; | |
1818 for (Dsymbol *s = this; s; s = s->parent) | |
1819 { | |
1820 //printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); | |
1821 ad = s->isMember(); | |
1822 if (ad) | |
1823 { //printf("test4\n"); | |
1824 break; | |
1825 } | |
1826 if (!s->parent || | |
1827 (!s->parent->isTemplateInstance())) | |
1828 { //printf("test5\n"); | |
1829 break; | |
1830 } | |
1831 } | |
1832 //printf("-FuncDeclaration::isMember2() %p\n", ad); | |
1833 return ad; | |
1834 } | |
1835 | |
1836 /***************************************** | |
1837 * Determine lexical level difference from 'this' to nested function 'fd'. | |
1838 * Error if this cannot call fd. | |
1839 * Returns: | |
1840 * 0 same level | |
1841 * -1 increase nesting by 1 (fd is nested within 'this') | |
1842 * >0 decrease nesting by number | |
1843 */ | |
1844 | |
1845 int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) | |
1846 { int level; | |
1847 Dsymbol *s; | |
1848 Dsymbol *fdparent; | |
1849 | |
1850 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); | |
1851 fdparent = fd->toParent2(); | |
1852 if (fdparent == this) | |
1853 return -1; | |
1854 s = this; | |
1855 level = 0; | |
1856 while (fd != s && fdparent != s->toParent2()) | |
1857 { | |
1858 //printf("\ts = '%s'\n", s->toChars()); | |
1859 FuncDeclaration *thisfd = s->isFuncDeclaration(); | |
1860 if (thisfd) | |
1861 { if (!thisfd->isNested() && !thisfd->vthis) | |
1862 goto Lerr; | |
1863 } | |
1864 else | |
1865 { | |
1866 ClassDeclaration *thiscd = s->isClassDeclaration(); | |
1867 if (thiscd) | |
1868 { if (!thiscd->isNested()) | |
1869 goto Lerr; | |
1870 } | |
1871 else | |
1872 goto Lerr; | |
1873 } | |
1874 | |
1875 s = s->toParent2(); | |
1876 assert(s); | |
1877 level++; | |
1878 } | |
1879 return level; | |
1880 | |
1881 Lerr: | |
1882 error(loc, "cannot access frame of function %s", fd->toChars()); | |
1883 return 1; | |
1884 } | |
1885 | |
1886 void FuncDeclaration::appendExp(Expression *e) | |
1887 { Statement *s; | |
1888 | |
1889 s = new ExpStatement(0, e); | |
1890 appendState(s); | |
1891 } | |
1892 | |
1893 void FuncDeclaration::appendState(Statement *s) | |
1894 { CompoundStatement *cs; | |
1895 | |
1896 if (!fbody) | |
1897 { Statements *a; | |
1898 | |
1899 a = new Statements(); | |
1900 fbody = new CompoundStatement(0, a); | |
1901 } | |
1902 cs = fbody->isCompoundStatement(); | |
1903 cs->statements->push(s); | |
1904 } | |
1905 | |
1906 | |
1907 int FuncDeclaration::isMain() | |
1908 { | |
1909 return ident == Id::main && | |
1910 linkage != LINKc && !isMember() && !isNested(); | |
1911 } | |
1912 | |
1913 int FuncDeclaration::isWinMain() | |
1914 { | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1915 //printf("FuncDeclaration::isWinMain() %s\n", toChars()); |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1916 #if 0 |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1917 int x = ident == Id::WinMain && |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1918 linkage != LINKc && !isMember(); |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1919 printf("%s\n", x ? "yes" : "no"); |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1920 return x; |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1921 #else |
159 | 1922 return ident == Id::WinMain && |
1923 linkage != LINKc && !isMember(); | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
1924 #endif |
159 | 1925 } |
1926 | |
1927 int FuncDeclaration::isDllMain() | |
1928 { | |
1929 return ident == Id::DllMain && | |
1930 linkage != LINKc && !isMember(); | |
1931 } | |
1932 | |
1933 int FuncDeclaration::isExport() | |
1934 { | |
1935 return protection == PROTexport; | |
1936 } | |
1937 | |
1938 int FuncDeclaration::isImportedSymbol() | |
1939 { | |
1940 //printf("isImportedSymbol()\n"); | |
1941 //printf("protection = %d\n", protection); | |
1942 return (protection == PROTexport) && !fbody; | |
1943 } | |
1944 | |
1945 // Determine if function goes into virtual function pointer table | |
1946 | |
1947 int FuncDeclaration::isVirtual() | |
1948 { | |
1949 #if 0 | |
1950 printf("FuncDeclaration::isVirtual(%s)\n", toChars()); | |
1951 printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); | |
1952 printf("result is %d\n", | |
1953 isMember() && | |
1954 !(isStatic() || protection == PROTprivate || protection == PROTpackage) && | |
1955 toParent()->isClassDeclaration()); | |
1956 #endif | |
1957 return isMember() && | |
1958 !(isStatic() || protection == PROTprivate || protection == PROTpackage) && | |
1959 toParent()->isClassDeclaration(); | |
1960 } | |
1961 | |
1962 int FuncDeclaration::isAbstract() | |
1963 { | |
1964 return storage_class & STCabstract; | |
1965 } | |
1966 | |
1967 int FuncDeclaration::isCodeseg() | |
1968 { | |
1969 return TRUE; // functions are always in the code segment | |
1970 } | |
1971 | |
1972 // Determine if function needs | |
1973 // a static frame pointer to its lexically enclosing function | |
1974 | |
1975 int FuncDeclaration::isNested() | |
1976 { | |
1977 //if (!toParent()) | |
1978 //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); | |
1979 //printf("\ttoParent() = '%s'\n", toParent()->toChars()); | |
1980 return ((storage_class & STCstatic) == 0) && | |
1981 (toParent2()->isFuncDeclaration() != NULL); | |
1982 } | |
1983 | |
1984 int FuncDeclaration::needThis() | |
1985 { | |
1986 //printf("FuncDeclaration::needThis() '%s'\n", toChars()); | |
1987 int i = isThis() != NULL; | |
1988 //printf("\t%d\n", i); | |
1989 if (!i && isFuncAliasDeclaration()) | |
1990 i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); | |
1991 return i; | |
1992 } | |
1993 | |
1994 int FuncDeclaration::addPreInvariant() | |
1995 { | |
1996 AggregateDeclaration *ad = isThis(); | |
1997 return (ad && | |
1998 //ad->isClassDeclaration() && | |
1999 global.params.useInvariants && | |
2000 (protection == PROTpublic || protection == PROTexport) && | |
2001 !naked); | |
2002 } | |
2003 | |
2004 int FuncDeclaration::addPostInvariant() | |
2005 { | |
2006 AggregateDeclaration *ad = isThis(); | |
2007 return (ad && | |
2008 ad->inv && | |
2009 //ad->isClassDeclaration() && | |
2010 global.params.useInvariants && | |
2011 (protection == PROTpublic || protection == PROTexport) && | |
2012 !naked); | |
2013 } | |
2014 | |
2015 /********************************** | |
2016 * Generate a FuncDeclaration for a runtime library function. | |
2017 */ | |
2018 | |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2019 // |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2020 // LLVMDC: Adjusted to give argument info to the runtime function decl. |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2021 // |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2022 |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2023 FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, char *name) |
159 | 2024 { |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2025 return genCfunc(args, treturn, Lexer::idPool(name)); |
159 | 2026 } |
2027 | |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2028 FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, Identifier *id) |
159 | 2029 { |
2030 FuncDeclaration *fd; | |
2031 TypeFunction *tf; | |
2032 Dsymbol *s; | |
2033 static DsymbolTable *st = NULL; | |
2034 | |
2035 //printf("genCfunc(name = '%s')\n", id->toChars()); | |
2036 //printf("treturn\n\t"); treturn->print(); | |
2037 | |
2038 // See if already in table | |
2039 if (!st) | |
2040 st = new DsymbolTable(); | |
2041 s = st->lookup(id); | |
2042 if (s) | |
2043 { | |
2044 fd = s->isFuncDeclaration(); | |
2045 assert(fd); | |
2046 assert(fd->type->nextOf()->equals(treturn)); | |
2047 } | |
2048 else | |
2049 { | |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
336
diff
changeset
|
2050 tf = new TypeFunction(args, treturn, 0, LINKc); |
159 | 2051 fd = new FuncDeclaration(0, 0, id, STCstatic, tf); |
2052 fd->protection = PROTpublic; | |
2053 fd->linkage = LINKc; | |
2054 | |
2055 st->insert(fd); | |
2056 } | |
2057 return fd; | |
2058 } | |
2059 | |
336 | 2060 const char *FuncDeclaration::kind() |
159 | 2061 { |
2062 return "function"; | |
2063 } | |
336 | 2064 |
159 | 2065 /******************************* |
2066 * Look at all the variables in this function that are referenced | |
2067 * by nested functions, and determine if a closure needs to be | |
2068 * created for them. | |
2069 */ | |
2070 | |
336 | 2071 #if DMDV2 |
159 | 2072 int FuncDeclaration::needsClosure() |
2073 { | |
2074 /* Need a closure for all the closureVars[] if any of the | |
2075 * closureVars[] are accessed by a | |
2076 * function that escapes the scope of this function. | |
2077 * We take the conservative approach and decide that any function that: | |
2078 * 1) is a virtual function | |
2079 * 2) has its address taken | |
2080 * 3) has a parent that escapes | |
336 | 2081 * |
2082 * Note that since a non-virtual function can be called by | |
2083 * a virtual one, if that non-virtual function accesses a closure | |
2084 * var, the closure still has to be taken. Hence, we check for isThis() | |
2085 * instead of isVirtual(). (thanks to David Friedman) | |
159 | 2086 */ |
2087 | |
2088 //printf("FuncDeclaration::needsClosure() %s\n", toChars()); | |
2089 for (int i = 0; i < closureVars.dim; i++) | |
2090 { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; | |
2091 assert(v->isVarDeclaration()); | |
2092 //printf("\tv = %s\n", v->toChars()); | |
2093 | |
2094 for (int j = 0; j < v->nestedrefs.dim; j++) | |
2095 { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; | |
2096 assert(f != this); | |
2097 | |
2098 //printf("\t\tf = %s, %d, %d\n", f->toChars(), f->isVirtual(), f->tookAddressOf); | |
336 | 2099 if (f->isThis() || f->tookAddressOf) |
159 | 2100 goto Lyes; // assume f escapes this function's scope |
2101 | |
2102 // Look to see if any parents of f that are below this escape | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
2103 for (Dsymbol *s = f->parent; s && s != this; s = s->parent) |
159 | 2104 { |
2105 f = s->isFuncDeclaration(); | |
336 | 2106 if (f && (f->isThis() || f->tookAddressOf)) |
159 | 2107 goto Lyes; |
2108 } | |
2109 } | |
2110 } | |
2111 return 0; | |
2112 | |
2113 Lyes: | |
2114 //printf("\tneeds closure\n"); | |
2115 return 1; | |
2116 } | |
2117 #endif | |
2118 | |
2119 /****************************** FuncAliasDeclaration ************************/ | |
2120 | |
2121 // Used as a way to import a set of functions from another scope into this one. | |
2122 | |
2123 FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) | |
2124 : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, | |
2125 (enum STC)funcalias->storage_class, funcalias->type) | |
2126 { | |
2127 assert(funcalias != this); | |
2128 this->funcalias = funcalias; | |
2129 } | |
2130 | |
336 | 2131 const char *FuncAliasDeclaration::kind() |
159 | 2132 { |
2133 return "function alias"; | |
2134 } | |
2135 | |
2136 | |
2137 /****************************** FuncLiteralDeclaration ************************/ | |
2138 | |
2139 FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, | |
2140 enum TOK tok, ForeachStatement *fes) | |
2141 : FuncDeclaration(loc, endloc, NULL, STCundefined, type) | |
2142 { | |
2143 char *id; | |
2144 | |
2145 if (fes) | |
2146 id = "__foreachbody"; | |
2147 else if (tok == TOKdelegate) | |
2148 id = "__dgliteral"; | |
2149 else | |
2150 id = "__funcliteral"; | |
2151 this->ident = Identifier::generateId(id); | |
2152 this->tok = tok; | |
2153 this->fes = fes; | |
2154 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); | |
2155 } | |
2156 | |
2157 Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) | |
2158 { | |
2159 FuncLiteralDeclaration *f; | |
2160 | |
2161 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); | |
2162 if (s) | |
2163 f = (FuncLiteralDeclaration *)s; | |
2164 else | |
2165 f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); | |
2166 FuncDeclaration::syntaxCopy(f); | |
2167 return f; | |
2168 } | |
2169 | |
2170 int FuncLiteralDeclaration::isNested() | |
2171 { | |
2172 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); | |
2173 return (tok == TOKdelegate); | |
2174 } | |
2175 | |
336 | 2176 int FuncLiteralDeclaration::isVirtual() |
2177 { | |
2178 return FALSE; | |
2179 } | |
2180 | |
2181 const char *FuncLiteralDeclaration::kind() | |
159 | 2182 { |
2183 // GCC requires the (char*) casts | |
2184 return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; | |
2185 } | |
2186 | |
2187 void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2188 { | |
2189 static Identifier *idfunc; | |
2190 static Identifier *iddel; | |
2191 | |
2192 if (!idfunc) | |
2193 idfunc = new Identifier("function", 0); | |
2194 if (!iddel) | |
2195 iddel = new Identifier("delegate", 0); | |
2196 | |
2197 type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); | |
2198 bodyToCBuffer(buf, hgs); | |
2199 } | |
2200 | |
2201 | |
2202 /********************************* CtorDeclaration ****************************/ | |
2203 | |
2204 CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) | |
2205 : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) | |
2206 { | |
2207 this->arguments = arguments; | |
2208 this->varargs = varargs; | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
468
diff
changeset
|
2209 //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); |
159 | 2210 } |
2211 | |
2212 Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) | |
2213 { | |
2214 CtorDeclaration *f; | |
2215 | |
2216 f = new CtorDeclaration(loc, endloc, NULL, varargs); | |
2217 | |
2218 f->outId = outId; | |
2219 f->frequire = frequire ? frequire->syntaxCopy() : NULL; | |
2220 f->fensure = fensure ? fensure->syntaxCopy() : NULL; | |
2221 f->fbody = fbody ? fbody->syntaxCopy() : NULL; | |
2222 assert(!fthrows); // deprecated | |
2223 | |
2224 f->arguments = Argument::arraySyntaxCopy(arguments); | |
2225 return f; | |
2226 } | |
2227 | |
2228 | |
2229 void CtorDeclaration::semantic(Scope *sc) | |
2230 { | |
2231 ClassDeclaration *cd; | |
2232 Type *tret; | |
2233 | |
2234 //printf("CtorDeclaration::semantic()\n"); | |
2235 if (type) | |
2236 return; | |
2237 | |
2238 sc = sc->push(); | |
2239 sc->stc &= ~STCstatic; // not a static constructor | |
2240 | |
2241 parent = sc->parent; | |
2242 Dsymbol *parent = toParent(); | |
2243 cd = parent->isClassDeclaration(); | |
2244 if (!cd) | |
2245 { | |
2246 error("constructors are only for class definitions"); | |
333
f7190d9eb70c
[svn r354] Fix the regressions between [346] and [353] by making constructors and destructors outside classes fatal errors.
ChristianK
parents:
305
diff
changeset
|
2247 fatal(); |
159 | 2248 tret = Type::tvoid; |
2249 } | |
2250 else | |
2251 tret = cd->type; //->referenceTo(); | |
2252 type = new TypeFunction(arguments, tret, varargs, LINKd); | |
336 | 2253 if (!originalType) |
2254 originalType = type; | |
159 | 2255 |
2256 sc->flags |= SCOPEctor; | |
2257 type = type->semantic(loc, sc); | |
2258 sc->flags &= ~SCOPEctor; | |
2259 | |
2260 // Append: | |
2261 // return this; | |
2262 // to the function body | |
2263 if (fbody) | |
2264 { Expression *e; | |
2265 Statement *s; | |
2266 | |
2267 e = new ThisExp(0); | |
2268 s = new ReturnStatement(0, e); | |
2269 fbody = new CompoundStatement(0, fbody, s); | |
2270 } | |
2271 | |
2272 FuncDeclaration::semantic(sc); | |
2273 | |
2274 sc->pop(); | |
2275 | |
2276 // See if it's the default constructor | |
2277 if (cd && varargs == 0 && Argument::dim(arguments) == 0) | |
2278 cd->defaultCtor = this; | |
2279 } | |
2280 | |
336 | 2281 const char *CtorDeclaration::kind() |
159 | 2282 { |
2283 return "constructor"; | |
2284 } | |
2285 | |
2286 char *CtorDeclaration::toChars() | |
2287 { | |
2288 return "this"; | |
2289 } | |
2290 | |
2291 int CtorDeclaration::isVirtual() | |
2292 { | |
2293 return FALSE; | |
2294 } | |
2295 | |
2296 int CtorDeclaration::addPreInvariant() | |
2297 { | |
2298 return FALSE; | |
2299 } | |
2300 | |
2301 int CtorDeclaration::addPostInvariant() | |
2302 { | |
2303 return (vthis && global.params.useInvariants); | |
2304 } | |
2305 | |
2306 | |
2307 void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2308 { | |
2309 buf->writestring("this"); | |
2310 Argument::argsToCBuffer(buf, hgs, arguments, varargs); | |
2311 bodyToCBuffer(buf, hgs); | |
2312 } | |
2313 | |
2314 /********************************* DtorDeclaration ****************************/ | |
2315 | |
2316 DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) | |
2317 : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) | |
2318 { | |
2319 } | |
2320 | |
2321 DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) | |
2322 : FuncDeclaration(loc, endloc, id, STCundefined, NULL) | |
2323 { | |
2324 } | |
2325 | |
2326 Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) | |
2327 { | |
2328 assert(!s); | |
2329 DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); | |
2330 return FuncDeclaration::syntaxCopy(dd); | |
2331 } | |
2332 | |
2333 | |
2334 void DtorDeclaration::semantic(Scope *sc) | |
2335 { | |
2336 ClassDeclaration *cd; | |
2337 | |
2338 parent = sc->parent; | |
2339 Dsymbol *parent = toParent(); | |
2340 cd = parent->isClassDeclaration(); | |
2341 if (!cd) | |
2342 { | |
2343 error("destructors only are for class definitions"); | |
333
f7190d9eb70c
[svn r354] Fix the regressions between [346] and [353] by making constructors and destructors outside classes fatal errors.
ChristianK
parents:
305
diff
changeset
|
2344 fatal(); |
159 | 2345 } |
2346 else | |
2347 cd->dtors.push(this); | |
2348 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); | |
2349 | |
2350 sc = sc->push(); | |
2351 sc->stc &= ~STCstatic; // not a static destructor | |
2352 sc->linkage = LINKd; | |
2353 | |
2354 FuncDeclaration::semantic(sc); | |
2355 | |
2356 sc->pop(); | |
2357 } | |
2358 | |
2359 int DtorDeclaration::overloadInsert(Dsymbol *s) | |
2360 { | |
2361 return FALSE; // cannot overload destructors | |
2362 } | |
2363 | |
2364 int DtorDeclaration::addPreInvariant() | |
2365 { | |
2366 return (vthis && global.params.useInvariants); | |
2367 } | |
2368 | |
2369 int DtorDeclaration::addPostInvariant() | |
2370 { | |
2371 return FALSE; | |
2372 } | |
2373 | |
2374 int DtorDeclaration::isVirtual() | |
2375 { | |
2376 /* This should be FALSE so that dtor's don't get put into the vtbl[], | |
2377 * but doing so will require recompiling everything. | |
2378 */ | |
2379 #if BREAKABI | |
2380 return FALSE; | |
2381 #else | |
2382 return FuncDeclaration::isVirtual(); | |
2383 #endif | |
2384 } | |
2385 | |
2386 void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2387 { | |
2388 if (hgs->hdrgen) | |
2389 return; | |
2390 buf->writestring("~this()"); | |
2391 bodyToCBuffer(buf, hgs); | |
2392 } | |
2393 | |
2394 /********************************* StaticCtorDeclaration ****************************/ | |
2395 | |
2396 StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) | |
2397 : FuncDeclaration(loc, endloc, | |
2398 Identifier::generateId("_staticCtor"), STCstatic, NULL) | |
2399 { | |
2400 } | |
2401 | |
2402 Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) | |
2403 { | |
2404 StaticCtorDeclaration *scd; | |
2405 | |
2406 assert(!s); | |
2407 scd = new StaticCtorDeclaration(loc, endloc); | |
2408 return FuncDeclaration::syntaxCopy(scd); | |
2409 } | |
2410 | |
2411 | |
2412 void StaticCtorDeclaration::semantic(Scope *sc) | |
2413 { | |
2414 //printf("StaticCtorDeclaration::semantic()\n"); | |
2415 | |
2416 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); | |
2417 | |
336 | 2418 /* If the static ctor appears within a template instantiation, |
2419 * it could get called multiple times by the module constructors | |
2420 * for different modules. Thus, protect it with a gate. | |
2421 */ | |
2422 if (inTemplateInstance()) | |
2423 { | |
2424 /* Add this prefix to the function: | |
2425 * static int gate; | |
2426 * if (++gate != 1) return; | |
2427 * Note that this is not thread safe; should not have threads | |
2428 * during static construction. | |
2429 */ | |
2430 Identifier *id = Lexer::idPool("__gate"); | |
2431 VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); | |
2432 v->storage_class = STCstatic; | |
2433 Statements *sa = new Statements(); | |
2434 Statement *s = new DeclarationStatement(0, v); | |
2435 sa->push(s); | |
2436 Expression *e = new IdentifierExp(0, id); | |
2437 e = new AddAssignExp(0, e, new IntegerExp(1)); | |
2438 e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); | |
2439 s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); | |
2440 sa->push(s); | |
2441 if (fbody) | |
2442 sa->push(fbody); | |
2443 fbody = new CompoundStatement(0, sa); | |
2444 } | |
2445 | |
159 | 2446 FuncDeclaration::semantic(sc); |
2447 | |
2448 // We're going to need ModuleInfo | |
2449 Module *m = getModule(); | |
2450 if (!m) | |
2451 m = sc->module; | |
2452 if (m) | |
2453 { m->needmoduleinfo = 1; | |
2454 #ifdef IN_GCC | |
2455 m->strictlyneedmoduleinfo = 1; | |
2456 #endif | |
2457 } | |
2458 } | |
2459 | |
2460 AggregateDeclaration *StaticCtorDeclaration::isThis() | |
2461 { | |
2462 return NULL; | |
2463 } | |
2464 | |
2465 int StaticCtorDeclaration::isStaticConstructor() | |
2466 { | |
2467 return TRUE; | |
2468 } | |
2469 | |
2470 int StaticCtorDeclaration::isVirtual() | |
2471 { | |
2472 return FALSE; | |
2473 } | |
2474 | |
2475 int StaticCtorDeclaration::addPreInvariant() | |
2476 { | |
2477 return FALSE; | |
2478 } | |
2479 | |
2480 int StaticCtorDeclaration::addPostInvariant() | |
2481 { | |
2482 return FALSE; | |
2483 } | |
2484 | |
2485 void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2486 { | |
2487 if (hgs->hdrgen) | |
2488 { buf->writestring("static this();\n"); | |
2489 return; | |
2490 } | |
2491 buf->writestring("static this()"); | |
2492 bodyToCBuffer(buf, hgs); | |
2493 } | |
2494 | |
2495 /********************************* StaticDtorDeclaration ****************************/ | |
2496 | |
2497 StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) | |
2498 : FuncDeclaration(loc, endloc, | |
2499 Identifier::generateId("_staticDtor"), STCstatic, NULL) | |
2500 { | |
336 | 2501 vgate = NULL; |
159 | 2502 } |
2503 | |
2504 Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) | |
2505 { | |
2506 StaticDtorDeclaration *sdd; | |
2507 | |
2508 assert(!s); | |
2509 sdd = new StaticDtorDeclaration(loc, endloc); | |
2510 return FuncDeclaration::syntaxCopy(sdd); | |
2511 } | |
2512 | |
2513 | |
2514 void StaticDtorDeclaration::semantic(Scope *sc) | |
2515 { | |
2516 ClassDeclaration *cd; | |
2517 Type *tret; | |
2518 | |
2519 cd = sc->scopesym->isClassDeclaration(); | |
2520 if (!cd) | |
2521 { | |
2522 } | |
2523 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); | |
2524 | |
336 | 2525 /* If the static ctor appears within a template instantiation, |
2526 * it could get called multiple times by the module constructors | |
2527 * for different modules. Thus, protect it with a gate. | |
2528 */ | |
2529 if (inTemplateInstance()) | |
2530 { | |
2531 /* Add this prefix to the function: | |
2532 * static int gate; | |
2533 * if (--gate != 0) return; | |
2534 * Increment gate during constructor execution. | |
2535 * Note that this is not thread safe; should not have threads | |
2536 * during static destruction. | |
2537 */ | |
2538 Identifier *id = Lexer::idPool("__gate"); | |
2539 VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); | |
2540 v->storage_class = STCstatic; | |
2541 Statements *sa = new Statements(); | |
2542 Statement *s = new DeclarationStatement(0, v); | |
2543 sa->push(s); | |
2544 Expression *e = new IdentifierExp(0, id); | |
2545 e = new AddAssignExp(0, e, new IntegerExp(-1)); | |
2546 e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); | |
2547 s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); | |
2548 sa->push(s); | |
2549 if (fbody) | |
2550 sa->push(fbody); | |
2551 fbody = new CompoundStatement(0, sa); | |
2552 vgate = v; | |
2553 } | |
2554 | |
159 | 2555 FuncDeclaration::semantic(sc); |
2556 | |
2557 // We're going to need ModuleInfo | |
2558 Module *m = getModule(); | |
2559 if (!m) | |
2560 m = sc->module; | |
2561 if (m) | |
2562 { m->needmoduleinfo = 1; | |
2563 #ifdef IN_GCC | |
2564 m->strictlyneedmoduleinfo = 1; | |
2565 #endif | |
2566 } | |
2567 } | |
2568 | |
2569 AggregateDeclaration *StaticDtorDeclaration::isThis() | |
2570 { | |
2571 return NULL; | |
2572 } | |
2573 | |
2574 int StaticDtorDeclaration::isStaticDestructor() | |
2575 { | |
2576 return TRUE; | |
2577 } | |
2578 | |
2579 int StaticDtorDeclaration::isVirtual() | |
2580 { | |
2581 return FALSE; | |
2582 } | |
2583 | |
2584 int StaticDtorDeclaration::addPreInvariant() | |
2585 { | |
2586 return FALSE; | |
2587 } | |
2588 | |
2589 int StaticDtorDeclaration::addPostInvariant() | |
2590 { | |
2591 return FALSE; | |
2592 } | |
2593 | |
2594 void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2595 { | |
2596 if (hgs->hdrgen) | |
2597 return; | |
2598 buf->writestring("static ~this()"); | |
2599 bodyToCBuffer(buf, hgs); | |
2600 } | |
2601 | |
2602 /********************************* InvariantDeclaration ****************************/ | |
2603 | |
2604 InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) | |
2605 : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) | |
2606 { | |
2607 } | |
2608 | |
2609 Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) | |
2610 { | |
2611 InvariantDeclaration *id; | |
2612 | |
2613 assert(!s); | |
2614 id = new InvariantDeclaration(loc, endloc); | |
2615 FuncDeclaration::syntaxCopy(id); | |
2616 return id; | |
2617 } | |
2618 | |
2619 | |
2620 void InvariantDeclaration::semantic(Scope *sc) | |
2621 { | |
2622 AggregateDeclaration *ad; | |
2623 Type *tret; | |
2624 | |
2625 parent = sc->parent; | |
2626 Dsymbol *parent = toParent(); | |
2627 ad = parent->isAggregateDeclaration(); | |
2628 if (!ad) | |
2629 { | |
2630 error("invariants only are for struct/union/class definitions"); | |
2631 return; | |
2632 } | |
2633 else if (ad->inv && ad->inv != this) | |
2634 { | |
2635 error("more than one invariant for %s", ad->toChars()); | |
2636 } | |
2637 ad->inv = this; | |
2638 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); | |
2639 | |
2640 sc = sc->push(); | |
2641 sc->stc &= ~STCstatic; // not a static invariant | |
2642 sc->incontract++; | |
2643 sc->linkage = LINKd; | |
2644 | |
2645 FuncDeclaration::semantic(sc); | |
2646 | |
2647 sc->pop(); | |
2648 } | |
2649 | |
2650 int InvariantDeclaration::isVirtual() | |
2651 { | |
2652 return FALSE; | |
2653 } | |
2654 | |
2655 int InvariantDeclaration::addPreInvariant() | |
2656 { | |
2657 return FALSE; | |
2658 } | |
2659 | |
2660 int InvariantDeclaration::addPostInvariant() | |
2661 { | |
2662 return FALSE; | |
2663 } | |
2664 | |
2665 void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2666 { | |
2667 if (hgs->hdrgen) | |
2668 return; | |
2669 buf->writestring("invariant"); | |
2670 bodyToCBuffer(buf, hgs); | |
2671 } | |
2672 | |
2673 | |
2674 /********************************* UnitTestDeclaration ****************************/ | |
2675 | |
2676 /******************************* | |
2677 * Generate unique unittest function Id so we can have multiple | |
2678 * instances per module. | |
2679 */ | |
2680 | |
2681 static Identifier *unitTestId() | |
2682 { | |
336 | 2683 return Lexer::uniqueId("__unittest"); |
159 | 2684 } |
2685 | |
2686 UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) | |
2687 : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) | |
2688 { | |
2689 } | |
2690 | |
2691 Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) | |
2692 { | |
2693 UnitTestDeclaration *utd; | |
2694 | |
2695 assert(!s); | |
2696 utd = new UnitTestDeclaration(loc, endloc); | |
2697 return FuncDeclaration::syntaxCopy(utd); | |
2698 } | |
2699 | |
2700 | |
2701 void UnitTestDeclaration::semantic(Scope *sc) | |
2702 { | |
2703 if (global.params.useUnitTests) | |
2704 { | |
2705 Type *tret; | |
2706 | |
2707 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); | |
2708 FuncDeclaration::semantic(sc); | |
2709 } | |
2710 | |
2711 // We're going to need ModuleInfo even if the unit tests are not | |
2712 // compiled in, because other modules may import this module and refer | |
2713 // to this ModuleInfo. | |
2714 Module *m = getModule(); | |
2715 if (!m) | |
2716 m = sc->module; | |
2717 if (m) | |
2718 m->needmoduleinfo = 1; | |
2719 } | |
2720 | |
2721 AggregateDeclaration *UnitTestDeclaration::isThis() | |
2722 { | |
2723 return NULL; | |
2724 } | |
2725 | |
2726 int UnitTestDeclaration::isVirtual() | |
2727 { | |
2728 return FALSE; | |
2729 } | |
2730 | |
2731 int UnitTestDeclaration::addPreInvariant() | |
2732 { | |
2733 return FALSE; | |
2734 } | |
2735 | |
2736 int UnitTestDeclaration::addPostInvariant() | |
2737 { | |
2738 return FALSE; | |
2739 } | |
2740 | |
2741 void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2742 { | |
2743 if (hgs->hdrgen) | |
2744 return; | |
2745 buf->writestring("unittest"); | |
2746 bodyToCBuffer(buf, hgs); | |
2747 } | |
2748 | |
2749 /********************************* NewDeclaration ****************************/ | |
2750 | |
2751 NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) | |
2752 : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) | |
2753 { | |
2754 this->arguments = arguments; | |
2755 this->varargs = varargs; | |
2756 } | |
2757 | |
2758 Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) | |
2759 { | |
2760 NewDeclaration *f; | |
2761 | |
2762 f = new NewDeclaration(loc, endloc, NULL, varargs); | |
2763 | |
2764 FuncDeclaration::syntaxCopy(f); | |
2765 | |
2766 f->arguments = Argument::arraySyntaxCopy(arguments); | |
2767 | |
2768 return f; | |
2769 } | |
2770 | |
2771 | |
2772 void NewDeclaration::semantic(Scope *sc) | |
2773 { | |
2774 ClassDeclaration *cd; | |
2775 Type *tret; | |
2776 | |
2777 //printf("NewDeclaration::semantic()\n"); | |
2778 | |
2779 parent = sc->parent; | |
2780 Dsymbol *parent = toParent(); | |
2781 cd = parent->isClassDeclaration(); | |
2782 if (!cd && !parent->isStructDeclaration()) | |
2783 { | |
2784 error("new allocators only are for class or struct definitions"); | |
2785 } | |
2786 tret = Type::tvoid->pointerTo(); | |
2787 type = new TypeFunction(arguments, tret, varargs, LINKd); | |
2788 | |
2789 type = type->semantic(loc, sc); | |
2790 assert(type->ty == Tfunction); | |
2791 | |
2792 // Check that there is at least one argument of type uint | |
2793 TypeFunction *tf = (TypeFunction *)type; | |
2794 if (Argument::dim(tf->parameters) < 1) | |
2795 { | |
2796 error("at least one argument of type uint expected"); | |
2797 } | |
2798 else | |
2799 { | |
2800 Argument *a = Argument::getNth(tf->parameters, 0); | |
2801 if (!a->type->equals(Type::tuns32)) | |
2802 error("first argument must be type uint, not %s", a->type->toChars()); | |
2803 } | |
2804 | |
2805 FuncDeclaration::semantic(sc); | |
2806 } | |
2807 | |
336 | 2808 const char *NewDeclaration::kind() |
159 | 2809 { |
2810 return "allocator"; | |
2811 } | |
2812 | |
2813 int NewDeclaration::isVirtual() | |
2814 { | |
2815 return FALSE; | |
2816 } | |
2817 | |
2818 int NewDeclaration::addPreInvariant() | |
2819 { | |
2820 return FALSE; | |
2821 } | |
2822 | |
2823 int NewDeclaration::addPostInvariant() | |
2824 { | |
2825 return FALSE; | |
2826 } | |
2827 | |
2828 void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2829 { | |
2830 buf->writestring("new"); | |
2831 Argument::argsToCBuffer(buf, hgs, arguments, varargs); | |
2832 bodyToCBuffer(buf, hgs); | |
2833 } | |
2834 | |
2835 | |
2836 /********************************* DeleteDeclaration ****************************/ | |
2837 | |
2838 DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) | |
2839 : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) | |
2840 { | |
2841 this->arguments = arguments; | |
2842 } | |
2843 | |
2844 Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) | |
2845 { | |
2846 DeleteDeclaration *f; | |
2847 | |
2848 f = new DeleteDeclaration(loc, endloc, NULL); | |
2849 | |
2850 FuncDeclaration::syntaxCopy(f); | |
2851 | |
2852 f->arguments = Argument::arraySyntaxCopy(arguments); | |
2853 | |
2854 return f; | |
2855 } | |
2856 | |
2857 | |
2858 void DeleteDeclaration::semantic(Scope *sc) | |
2859 { | |
2860 ClassDeclaration *cd; | |
2861 | |
2862 //printf("DeleteDeclaration::semantic()\n"); | |
2863 | |
2864 parent = sc->parent; | |
2865 Dsymbol *parent = toParent(); | |
2866 cd = parent->isClassDeclaration(); | |
2867 if (!cd && !parent->isStructDeclaration()) | |
2868 { | |
2869 error("new allocators only are for class or struct definitions"); | |
2870 } | |
2871 type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); | |
2872 | |
2873 type = type->semantic(loc, sc); | |
2874 assert(type->ty == Tfunction); | |
2875 | |
2876 // Check that there is only one argument of type void* | |
2877 TypeFunction *tf = (TypeFunction *)type; | |
2878 if (Argument::dim(tf->parameters) != 1) | |
2879 { | |
2880 error("one argument of type void* expected"); | |
2881 } | |
2882 else | |
2883 { | |
2884 Argument *a = Argument::getNth(tf->parameters, 0); | |
2885 if (!a->type->equals(Type::tvoid->pointerTo())) | |
2886 error("one argument of type void* expected, not %s", a->type->toChars()); | |
2887 } | |
2888 | |
2889 FuncDeclaration::semantic(sc); | |
2890 } | |
2891 | |
336 | 2892 const char *DeleteDeclaration::kind() |
159 | 2893 { |
2894 return "deallocator"; | |
2895 } | |
2896 | |
2897 int DeleteDeclaration::isDelete() | |
2898 { | |
2899 return TRUE; | |
2900 } | |
2901 | |
2902 int DeleteDeclaration::isVirtual() | |
2903 { | |
2904 return FALSE; | |
2905 } | |
2906 | |
2907 int DeleteDeclaration::addPreInvariant() | |
2908 { | |
2909 return FALSE; | |
2910 } | |
2911 | |
2912 int DeleteDeclaration::addPostInvariant() | |
2913 { | |
2914 return FALSE; | |
2915 } | |
2916 | |
2917 void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2918 { | |
2919 buf->writestring("delete"); | |
2920 Argument::argsToCBuffer(buf, hgs, arguments, 0); | |
2921 bodyToCBuffer(buf, hgs); | |
2922 } | |
2923 | |
2924 | |
2925 | |
2926 |