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