root/trunk/src/struct.c

Revision 781, 18.5 kB (checked in by walter, 1 year ago)

bugzilla 5110 Excess attribute propagation of structs and classes

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