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