1:
2: // Compiler implementation of the D programming language
3: // Copyright (c) 1999-2011 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: static char __file__[] = __FILE__; /* for tassert.h */
13: #include "tassert.h"
14:
15: #include "root.h"
16: #include "aggregate.h"
17: #include "scope.h"
18: #include "mtype.h"
19: #include "declaration.h"
20: #include "module.h"
21: #include "id.h"
22: #include "statement.h"
23: #include "template.h"
24:
25: /********************************* AggregateDeclaration ****************************/
26:
27: AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
28: : ScopeDsymbol(id)
29: {
30: this->loc = loc;
31:
32: storage_class = 0;
33: protection = PROTpublic;
34: type = NULL;
35: handle = NULL;
36: structsize = 0; // size of struct
37: alignsize = 0; // size of struct for alignment purposes
38: structalign = 0; // struct member alignment in effect
39: hasUnions = 0;
40: sizeok = 0; // size not determined yet
41: deferred = NULL;
42: isdeprecated = 0;
43: inv = NULL;
44: aggNew = NULL;
45: aggDelete = NULL;
46:
47: stag = NULL;
48: sinit = NULL;
49: isnested = 0;
50: vthis = NULL;
51:
52: #if DMDV2
53: ctor = NULL;
54: defaultCtor = NULL;
55: aliasthis = NULL;
56: noDefaultCtor = FALSE;
57: #endif
58: dtor = NULL;
59: }
60:
61: enum PROT AggregateDeclaration::prot()
62: {
63: return protection;
64: }
65:
66: void AggregateDeclaration::semantic2(Scope *sc)
67: {
68: //printf("AggregateDeclaration::semantic2(%s)\n", toChars());
69: if (scope && members)
70: { error("has forward references");
71: return;
72: }
73: if (members)
74: {
75: sc = sc->push(this);
76: for (size_t i = 0; i < members->dim; i++)
77: {
78: Dsymbol *s = members->tdata()[i];
79: s->semantic2(sc);
80: }
81: sc->pop();
82: }
83: }
84:
85: void AggregateDeclaration::semantic3(Scope *sc)
86: { int i;
87:
88: //printf("AggregateDeclaration::semantic3(%s)\n", toChars());
89: if (members)
90: {
91: sc = sc->push(this);
92: for (i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
93: {
94: Dsymbol *s = members->tdata()[i];
95: s->semantic3(sc);
96: }
97: sc->pop();
98: }
99: }
100:
101: void AggregateDeclaration::inlineScan()
102: { int i;
103:
104: //printf("AggregateDeclaration::inlineScan(%s)\n", toChars());
105: if (members)
106: {
107: for (i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
108: {
109: Dsymbol *s = members->tdata()[i];
110: //printf("inline scan aggregate symbol '%s'\n", s->toChars());
111: s->inlineScan();
112: }
113: }
114: }
115:
116: unsigned AggregateDeclaration::size(Loc loc)
117: {
118: //printf("AggregateDeclaration::size() = %d\n", structsize);
119: if (!members)
120: error(loc, "unknown size");
121: if (sizeok != 1 && scope)
122: semantic(NULL);
123: if (sizeok != 1)
124: { error(loc, "no size yet for forward reference");
125: //*(char*)0=0;
126: }
127: return structsize;
128: }
129:
130: Type *AggregateDeclaration::getType()
131: {
132: return type;
133: }
134:
135: int AggregateDeclaration::isDeprecated()
136: {
137: return isdeprecated;
138: }
139:
140: /****************************
141: * Do byte or word alignment as necessary.
142: * Align sizes of 0, as we may not know array sizes yet.
143: */
144:
145: void AggregateDeclaration::alignmember(
146: unsigned salign, // struct alignment that is in effect
147: unsigned size, // alignment requirement of field
148: unsigned *poffset)
149: {
150: //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset);
151: if (salign > 1)
152: {
153: assert(size != 3);
154: int sa = size;
155: if (sa == 0 || salign < sa)
warning C4018: '<' : signed/unsigned mismatch
156: sa = salign;
157: *poffset = (*poffset + sa - 1) & ~(sa - 1);
158: }
159: //printf("result = %d\n",offset);
160: }
161:
162:
163: void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v)
164: {
165: unsigned memsize; // size of member
166: unsigned memalignsize; // size of member for alignment purposes
167: unsigned xalign; // alignment boundaries
168:
169: //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars());
170: assert(!(v->storage_class & (STCstatic | STCextern | STCparameter | STCtls)));
171:
172: // Check for forward referenced types which will fail the size() call
173: Type *t = v->type->toBasetype();
174: if (v->storage_class & STCref)
175: { // References are the size of a pointer
176: t = Type::tvoidptr;
177: }
178: if (t->ty == Tstruct /*&& isStructDeclaration()*/)
179: { TypeStruct *ts = (TypeStruct *)t;
180: #if DMDV2
181: if (ts->sym == this)
182: {
183: error("cannot have field %s with same struct type", v->toChars());
184: }
185: #endif
186:
187: if (ts->sym->sizeok != 1 && ts->sym->scope)
188: ts->sym->semantic(NULL);
189: if (ts->sym->sizeok != 1)
190: {
191: sizeok = 2; // cannot finish; flag as forward referenced
192: return;
193: }
194: }
195: if (t->ty == Tident)
196: {
197: sizeok = 2; // cannot finish; flag as forward referenced
198: return;
199: }
200:
201: memsize = t->size(loc);
warning C4244: '=' : conversion from 'd_uns64' to 'unsigned int', possible loss of data
202: memalignsize = t->alignsize();
203: xalign = t->memalign(sc->structalign);
204: #if 0
205: alignmember(xalign, memalignsize, &sc->offset);
206: v->offset = sc->offset;
207: sc->offset += memsize;
208: if (sc->offset > structsize)
209: structsize = sc->offset;
210: #else
211: unsigned ofs = sc->offset;
212: alignmember(xalign, memalignsize, &ofs);
213: v->offset = ofs;
214: ofs += memsize;
215: if (ofs > structsize)
216: structsize = ofs;
217: if (!isUnionDeclaration())
218: sc->offset = ofs;
219: #endif
220: if (global.params.is64bit && sc->structalign == 8 && memalignsize == 16)
221: /* Not sure how to handle this */
222: ;
223: else if (sc->structalign < memalignsize)
224: memalignsize = sc->structalign;
225: if (alignsize < memalignsize)
226: alignsize = memalignsize;
227: //printf("\t%s: alignsize = %d\n", toChars(), alignsize);
228:
229: v->storage_class |= STCfield;
230: //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize);
231: fields.push(v);
232: }
233:
234:
235: /****************************************
236: * Returns !=0 if there's an extra member which is the 'this'
237: * pointer to the enclosing context (enclosing aggregate or function)
238: */
239:
240: int AggregateDeclaration::isNested()
241: {
242: return isnested;
243: }
244:
245: /****************************************
246: * If field[indx] is not part of a union, return indx.
247: * Otherwise, return the lowest field index of the union.
248: */
249: int AggregateDeclaration::firstFieldInUnion(int indx)
250: {
251: if (isUnionDeclaration())
252: return 0;
253: VarDeclaration * vd = fields.tdata()[indx];
254: int firstNonZero = indx; // first index in the union with non-zero size
255: for (; ;)
256: {
257: if (indx == 0)
258: return firstNonZero;
259: VarDeclaration * v = fields.tdata()[indx - 1];
260: if (v->offset != vd->offset)
261: return firstNonZero;
262: --indx;
263: /* If it is a zero-length field, it's ambiguous: we don't know if it is
264: * in the union unless we find an earlier non-zero sized field with the
265: * same offset.
266: */
267: if (v->size(loc) != 0)
268: firstNonZero = indx;
269: }
270: }
271:
272: /****************************************
273: * Count the number of fields starting at firstIndex which are part of the
274: * same union as field[firstIndex]. If not a union, return 1.
275: */
276: int AggregateDeclaration::numFieldsInUnion(int firstIndex)
277: {
278: VarDeclaration * vd = fields.tdata()[firstIndex];
279: /* If it is a zero-length field, AND we can't find an earlier non-zero
280: * sized field with the same offset, we assume it's not part of a union.
281: */
282: if (vd->size(loc) == 0 && !isUnionDeclaration() &&
283: firstFieldInUnion(firstIndex) == firstIndex)
284: return 1;
285: int count = 1;
286: for (int i = firstIndex+1; i < fields.dim; ++i)
warning C4018: '<' : signed/unsigned mismatch
287: {
288: VarDeclaration * v = fields.tdata()[i];
289: // If offsets are different, they are not in the same union
290: if (v->offset != vd->offset)
291: break;
292: ++count;
293: }
294: return count;
295: }
296:
297: /********************************* StructDeclaration ****************************/
298:
299: StructDeclaration::StructDeclaration(Loc loc, Identifier *id)
300: : AggregateDeclaration(loc, id)
301: {
302: zeroInit = 0; // assume false until we do semantic processing
303: #if DMDV2
304: hasIdentityAssign = 0;
305: cpctor = NULL;
306: postblit = NULL;
307: eq = NULL;
308: #endif
309:
310: // For forward references
311: type = new TypeStruct(this);
312: }
313:
314: Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
315: {
316: StructDeclaration *sd;
317:
318: if (s)
319: sd = (StructDeclaration *)s;
320: else
321: sd = new StructDeclaration(loc, ident);
322: ScopeDsymbol::syntaxCopy(sd);
323: return sd;
324: }
325:
326: void StructDeclaration::semantic(Scope *sc)
327: {
328: Scope *sc2;
329:
330: //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
331:
332: //static int count; if (++count == 20) halt();
333:
334: assert(type);
335: if (!members) // if forward reference
336: return;
337:
338: if (symtab)
339: { if (sizeok == 1 || !scope)
340: { //printf("already completed\n");
341: scope = NULL;
342: return; // semantic() already completed
343: }
344: }
345: else
346: symtab = new DsymbolTable();
347:
348: Scope *scx = NULL;
349: if (scope)
350: { sc = scope;
351: scx = scope; // save so we don't make redundant copies
352: scope = NULL;
353: }
354:
355: unsigned dprogress_save = Module::dprogress;
356:
357: parent = sc->parent;
358: type = type->semantic(loc, sc);
359: #if STRUCTTHISREF
360: handle = type;
361: #else
362: handle = type->pointerTo();
363: #endif
364: structalign = sc->structalign;
365: protection = sc->protection;
366: storage_class |= sc->stc;
367: if (sc->stc & STCdeprecated)
368: isdeprecated = 1;
369: assert(!isAnonymous());
370: if (sc->stc & STCabstract)
371: error("structs, unions cannot be abstract");
372: #if DMDV2
373: if (storage_class & STCimmutable)
374: type = type->addMod(MODimmutable);
375: if (storage_class & STCconst)
376: type = type->addMod(MODconst);
377: if (storage_class & STCshared)
378: type = type->addMod(MODshared);
379: #endif
380:
381: if (sizeok == 0) // if not already done the addMember step
382: {
383: int hasfunctions = 0;
384: for (int i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
385: {
386: Dsymbol *s = members->tdata()[i];
387: //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
388: s->addMember(sc, this, 1);
389: if (s->isFuncDeclaration())
390: hasfunctions = 1;
391: }
392:
393: // If nested struct, add in hidden 'this' pointer to outer scope
394: if (hasfunctions && !(storage_class & STCstatic))
395: { Dsymbol *s = toParent2();
396: if (s)
397: {
398: AggregateDeclaration *ad = s->isAggregateDeclaration();
399: FuncDeclaration *fd = s->isFuncDeclaration();
400:
401: TemplateInstance *ti;
402: if (ad && (ti = ad->parent->isTemplateInstance()) != NULL && ti->isnested || fd)
403: { isnested = 1;
404: Type *t;
405: if (ad)
406: t = ad->handle;
407: else if (fd)
408: { AggregateDeclaration *ad = fd->isMember2();
warning C6246: Local declaration of 'ad' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '398' of 'c:\projects\extern\d\dmd\src\struct.c': Lines: 398
409: if (ad)
410: t = ad->handle;
411: else
412: t = Type::tvoidptr;
413: }
414: else
415: assert(0);
416: if (t->ty == Tstruct)
417: t = Type::tvoidptr; // t should not be a ref type
418: assert(!vthis);
419: vthis = new ThisDeclaration(loc, t);
420: //vthis->storage_class |= STCref;
421: members->push(vthis);
422: }
423: }
424: }
425: }
426:
427: sizeok = 0;
428: sc2 = sc->push(this);
429: sc2->stc &= STCsafe | STCtrusted | STCsystem;
430: sc2->parent = this;
431: if (isUnionDeclaration())
432: sc2->inunion = 1;
433: sc2->protection = PROTpublic;
434: sc2->explicitProtection = 0;
435:
436: int members_dim = members->dim;
437:
438: /* Set scope so if there are forward references, we still might be able to
439: * resolve individual members like enums.
440: */
441: for (int i = 0; i < members_dim; i++)
442: { Dsymbol *s = members->tdata()[i];
443: /* There are problems doing this in the general case because
444: * Scope keeps track of things like 'offset'
445: */
446: if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident))
447: {
448: //printf("setScope %s %s\n", s->kind(), s->toChars());
449: s->setScope(sc2);
450: }
451: }
452:
453: for (int i = 0; i < members_dim; i++)
454: {
455: Dsymbol *s = members->tdata()[i];
456: s->semantic(sc2);
457: #if 0
458: if (sizeok == 2)
459: { //printf("forward reference\n");
460: break;
461: }
462: #endif
463:
464: #if 0 /* Decided to allow this because if the field is initialized by copying it from
465: * a correctly initialized struct, it will work.
466: */
467: Type *t;
468: if (s->isDeclaration() &&
469: (t = s->isDeclaration()->type) != NULL &&
470: t->toBasetype()->ty == Tstruct)
471: { StructDeclaration *sd = (StructDeclaration *)t->toDsymbol(sc);
472: if (sd->isnested)
473: error("inner struct %s cannot be the type for field %s as it must embed a reference to its enclosing %s",
474: sd->toChars(), s->toChars(), sd->toParent2()->toPrettyChars());
475: }
476: #endif
477: }
478:
479: #if DMDV1
480: /* This doesn't work for DMDV2 because (ref S) and (S) parameter
481: * lists will overload the same.
482: */
483: /* The TypeInfo_Struct is expecting an opEquals and opCmp with
484: * a parameter that is a pointer to the struct. But if there
485: * isn't one, but is an opEquals or opCmp with a value, write
486: * another that is a shell around the value:
487: * int opCmp(struct *p) { return opCmp(*p); }
488: */
489:
490: TypeFunction *tfeqptr;
491: {
492: Parameters *arguments = new Parameters;
493: Parameter *arg = new Parameter(STCin, handle, Id::p, NULL);
494:
495: arguments->push(arg);
496: tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
497: tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc);
498: }
499:
500: TypeFunction *tfeq;
501: {
502: Parameters *arguments = new Parameters;
503: Parameter *arg = new Parameter(STCin, type, NULL, NULL);
504:
505: arguments->push(arg);
506: tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
507: tfeq = (TypeFunction *)tfeq->semantic(0, sc);
508: }
509:
510: Identifier *id = Id::eq;
511: for (int i = 0; i < 2; i++)
512: {
513: Dsymbol *s = search_function(this, id);
514: FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
515: if (fdx)
516: { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
517: if (!fd)
518: { fd = fdx->overloadExactMatch(tfeq);
519: if (fd)
520: { // Create the thunk, fdptr
521: FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
522: Expression *e = new IdentifierExp(loc, Id::p);
523: e = new PtrExp(loc, e);
524: Expressions *args = new Expressions();
525: args->push(e);
526: e = new IdentifierExp(loc, id);
527: e = new CallExp(loc, e, args);
528: fdptr->fbody = new ReturnStatement(loc, e);
529: ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
530: assert(s);
531: s->members->push(fdptr);
532: fdptr->addMember(sc, s, 1);
533: fdptr->semantic(sc2);
534: }
535: }
536: }
537:
538: id = Id::cmp;
539: }
540: #endif
541: #if DMDV2
542: /* Try to find the opEquals function. Build it if necessary.
543: */
544: TypeFunction *tfeqptr;
545: { // bool opEquals(const T*) const;
546: Parameters *parameters = new Parameters;
warning C6211: Leaking memory 'parameters' due to an exception. Consider using a local catch block to clean up memory: Lines: 328, 334, 335, 338, 339, 348, 349, 350, 351, 352, 355, 357, 358, 360, 364, 365, 366, 367, 368, 369, 370, 371, 373, 374, 375, 376, 377, 378, 381, 427, 428, 429, 430, 431, 432, 433, 434, 436, 441, 453, 544, 546, 549
547: #if STRUCTTHISREF
548: // bool opEquals(ref const T) const;
549: Parameter *param = new Parameter(STCref, type->constOf(), NULL, NULL);
550: #else
551: // bool opEquals(const T*) const;
552: Parameter *param = new Parameter(STCin, type->pointerTo(), NULL, NULL);
553: #endif
554:
555: parameters->push(param);
556: tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd);
557: tfeqptr->mod = MODconst;
558: tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc2);
559:
560: Dsymbol *s = search_function(this, Id::eq);
561: FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
562: if (fdx)
563: {
564: eq = fdx->overloadExactMatch(tfeqptr);
565: if (!eq)
566: fdx->error("type signature should be %s not %s", tfeqptr->toChars(), fdx->type->toChars());
567: }
568:
569: TemplateDeclaration *td = s ? s->isTemplateDeclaration() : NULL;
570: // BUG: should also check that td is a function template, not just a template
571:
572: if (!eq && !td)
573: eq = buildOpEquals(sc2);
574: }
575:
576: dtor = buildDtor(sc2);
577: postblit = buildPostBlit(sc2);
578: cpctor = buildCpCtor(sc2);
579: buildOpAssign(sc2);
580: #endif
581:
582: sc2->pop();
583:
584: if (sizeok == 2)
585: { // semantic() failed because of forward references.
586: // Unwind what we did, and defer it for later
587: fields.setDim(0);
588: structsize = 0;
589: alignsize = 0;
590: structalign = 0;
591:
592: scope = scx ? scx : new Scope(*sc);
593: scope->setNoFree();
594: scope->module->addDeferredSemantic(this);
595:
596: Module::dprogress = dprogress_save;
597: //printf("\tdeferring %s\n", toChars());
598: return;
599: }
600:
601: // 0 sized struct's are set to 1 byte
602: if (structsize == 0)
603: {
604: structsize = 1;
605: alignsize = 1;
606: }
607:
608: // Round struct size up to next alignsize boundary.
609: // This will ensure that arrays of structs will get their internals
610: // aligned properly.
611: structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
612:
613: sizeok = 1;
614: Module::dprogress++;
615:
616: //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
617:
618: // Determine if struct is all zeros or not
619: zeroInit = 1;
620: for (int i = 0; i < fields.dim; i++)
warning C4018: '<' : signed/unsigned mismatch
621: {
622: Dsymbol *s = fields.tdata()[i];
623: VarDeclaration *vd = s->isVarDeclaration();
624: if (vd && !vd->isDataseg())
625: {
626: if (vd->init)
627: {
628: // Should examine init to see if it is really all 0's
629: zeroInit = 0;
630: break;
631: }
632: else
633: {
634: if (!vd->type->isZeroInit(loc))
635: {
636: zeroInit = 0;
637: break;
638: }
639: }
640: }
641: }
642:
643: /* Look for special member functions.
644: */
645: #if DMDV2
646: ctor = search(0, Id::ctor, 0);
647: #endif
648: inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0);
649: aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
650: aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
651:
652: if (sc->func)
653: {
654: semantic2(sc);
655: semantic3(sc);
656: }
657: if (deferred)
658: {
659: deferred->semantic2(sc);
660: deferred->semantic3(sc);
661: }
662: }
663:
664: Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags)
665: {
666: //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars());
667:
668: if (scope && !symtab)
669: semantic(scope);
670:
671: if (!members || !symtab)
672: {
673: error("is forward referenced when looking for '%s'", ident->toChars());
674: return NULL;
675: }
676:
677: return ScopeDsymbol::search(loc, ident, flags);
678: }
679:
680: void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
681: { int i;
682:
683: buf->printf("%s ", kind());
684: if (!isAnonymous())
685: buf->writestring(toChars());
686: if (!members)
687: {
688: buf->writeByte(';');
689: buf->writenl();
690: return;
691: }
692: buf->writenl();
693: buf->writeByte('{');
694: buf->writenl();
695: for (i = 0; i < members->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
696: {
697: Dsymbol *s = members->tdata()[i];
698:
699: buf->writestring(" ");
700: s->toCBuffer(buf, hgs);
701: }
702: buf->writeByte('}');
703: buf->writenl();
704: }
705:
706:
707: const char *StructDeclaration::kind()
708: {
709: return "struct";
710: }
711:
712: /********************************* UnionDeclaration ****************************/
713:
714: UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
715: : StructDeclaration(loc, id)
716: {
717: hasUnions = 1;
718: }
719:
720: Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
721: {
722: UnionDeclaration *ud;
723:
724: if (s)
725: ud = (UnionDeclaration *)s;
726: else
727: ud = new UnionDeclaration(loc, ident);
728: StructDeclaration::syntaxCopy(ud);
729: return ud;
730: }
731:
732:
733: const char *UnionDeclaration::kind()
734: {
735: return "union";
736: }
737:
738:
739: