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