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