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