1587
|
1
|
|
2 // Compiler implementation of the D programming language
|
|
3 // Copyright (c) 1999-2009 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 "root.h"
|
|
15 #include "aggregate.h"
|
|
16 #include "scope.h"
|
|
17 #include "mtype.h"
|
|
18 #include "declaration.h"
|
|
19 #include "module.h"
|
|
20 #include "id.h"
|
|
21 #include "statement.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 #if IN_DMD
|
|
45 stag = NULL;
|
|
46 sinit = NULL;
|
|
47 #endif
|
|
48 #if DMDV2
|
|
49 dtor = NULL;
|
|
50
|
|
51 ctor = NULL;
|
|
52 defaultCtor = NULL;
|
|
53 #endif
|
|
54
|
|
55 #if IN_LLVM
|
|
56 availableExternally = true; // assume this unless proven otherwise
|
|
57 #endif
|
|
58 }
|
|
59
|
|
60 enum PROT AggregateDeclaration::prot()
|
|
61 {
|
|
62 return protection;
|
|
63 }
|
|
64
|
|
65 void AggregateDeclaration::semantic2(Scope *sc)
|
|
66 {
|
|
67 //printf("AggregateDeclaration::semantic2(%s)\n", toChars());
|
|
68 if (scope && members)
|
|
69 { error("has forward references");
|
|
70 return;
|
|
71 }
|
|
72 if (members)
|
|
73 {
|
|
74 sc = sc->push(this);
|
|
75 for (size_t i = 0; i < members->dim; i++)
|
|
76 {
|
|
77 Dsymbol *s = (Dsymbol *)members->data[i];
|
|
78 s->semantic2(sc);
|
|
79 }
|
|
80 sc->pop();
|
|
81 }
|
|
82 }
|
|
83
|
|
84 void AggregateDeclaration::semantic3(Scope *sc)
|
|
85 { int i;
|
|
86
|
|
87 // LDC
|
|
88 if (!global.params.useAvailableExternally)
|
|
89 availableExternally = false;
|
|
90
|
|
91 //printf("AggregateDeclaration::semantic3(%s)\n", toChars());
|
|
92 if (members)
|
|
93 {
|
|
94 sc = sc->push(this);
|
|
95 for (i = 0; i < members->dim; i++)
|
|
96 {
|
|
97 Dsymbol *s = (Dsymbol *)members->data[i];
|
|
98 s->semantic3(sc);
|
|
99 }
|
|
100 sc->pop();
|
|
101 }
|
|
102 }
|
|
103
|
|
104 void AggregateDeclaration::inlineScan()
|
|
105 { int i;
|
|
106
|
|
107 //printf("AggregateDeclaration::inlineScan(%s)\n", toChars());
|
|
108 if (members)
|
|
109 {
|
|
110 for (i = 0; i < members->dim; i++)
|
|
111 {
|
|
112 Dsymbol *s = (Dsymbol *)members->data[i];
|
|
113 //printf("inline scan aggregate symbol '%s'\n", s->toChars());
|
|
114 s->inlineScan();
|
|
115 }
|
|
116 }
|
|
117 }
|
|
118
|
|
119 unsigned AggregateDeclaration::size(Loc loc)
|
|
120 {
|
|
121 //printf("AggregateDeclaration::size() = %d\n", structsize);
|
|
122 if (!members)
|
|
123 error(loc, "unknown size");
|
|
124 if (sizeok != 1)
|
|
125 { error(loc, "no size yet for forward reference");
|
|
126 //*(char*)0=0;
|
|
127 }
|
|
128 return structsize;
|
|
129 }
|
|
130
|
|
131 Type *AggregateDeclaration::getType()
|
|
132 {
|
|
133 return type;
|
|
134 }
|
|
135
|
|
136 int AggregateDeclaration::isDeprecated()
|
|
137 {
|
|
138 return isdeprecated;
|
|
139 }
|
|
140
|
|
141 /****************************
|
|
142 * Do byte or word alignment as necessary.
|
|
143 * Align sizes of 0, as we may not know array sizes yet.
|
|
144 */
|
|
145
|
|
146 void AggregateDeclaration::alignmember(
|
|
147 unsigned salign, // struct alignment that is in effect
|
|
148 unsigned size, // alignment requirement of field
|
|
149 unsigned *poffset)
|
|
150 {
|
|
151 //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset);
|
|
152 if (salign > 1)
|
|
153 {
|
|
154 assert(size != 3);
|
|
155 int sa = size;
|
|
156 if (sa == 0 || salign < sa)
|
|
157 sa = salign;
|
|
158 *poffset = (*poffset + sa - 1) & ~(sa - 1);
|
|
159 }
|
|
160 //printf("result = %d\n",offset);
|
|
161 }
|
|
162
|
|
163
|
|
164 void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v)
|
|
165 {
|
|
166 unsigned memsize; // size of member
|
|
167 unsigned memalignsize; // size of member for alignment purposes
|
|
168 unsigned xalign; // alignment boundaries
|
|
169
|
|
170 //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars());
|
|
171
|
|
172 // Check for forward referenced types which will fail the size() call
|
|
173 Type *t = v->type->toBasetype();
|
|
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)
|
|
184 {
|
|
185 sizeok = 2; // cannot finish; flag as forward referenced
|
|
186 return;
|
|
187 }
|
|
188 }
|
|
189 if (t->ty == Tident)
|
|
190 {
|
|
191 sizeok = 2; // cannot finish; flag as forward referenced
|
|
192 return;
|
|
193 }
|
|
194
|
|
195 memsize = v->type->size(loc);
|
|
196 memalignsize = v->type->alignsize();
|
|
197 xalign = v->type->memalign(sc->structalign);
|
|
198 alignmember(xalign, memalignsize, &sc->offset);
|
|
199 v->offset = sc->offset;
|
|
200 sc->offset += memsize;
|
|
201 if (sc->offset > structsize)
|
|
202 structsize = sc->offset;
|
|
203 if (sc->structalign < memalignsize)
|
|
204 memalignsize = sc->structalign;
|
|
205 if (alignsize < memalignsize)
|
|
206 alignsize = memalignsize;
|
|
207 //printf("\talignsize = %d\n", alignsize);
|
|
208
|
|
209 v->storage_class |= STCfield;
|
|
210 //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize);
|
|
211 fields.push(v);
|
|
212 }
|
|
213
|
|
214
|
|
215 /********************************* StructDeclaration ****************************/
|
|
216
|
|
217 StructDeclaration::StructDeclaration(Loc loc, Identifier *id)
|
|
218 : AggregateDeclaration(loc, id)
|
|
219 {
|
|
220 zeroInit = 0; // assume false until we do semantic processing
|
|
221 #if DMDV2
|
|
222 hasIdentityAssign = 0;
|
|
223 cpctor = NULL;
|
|
224 postblit = NULL;
|
|
225 #endif
|
|
226
|
|
227 // For forward references
|
|
228 type = new TypeStruct(this);
|
|
229 }
|
|
230
|
|
231 Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
|
|
232 {
|
|
233 StructDeclaration *sd;
|
|
234
|
|
235 if (s)
|
|
236 sd = (StructDeclaration *)s;
|
|
237 else
|
|
238 sd = new StructDeclaration(loc, ident);
|
|
239 ScopeDsymbol::syntaxCopy(sd);
|
|
240 return sd;
|
|
241 }
|
|
242
|
|
243 void StructDeclaration::semantic(Scope *sc)
|
|
244 { int i;
|
|
245 Scope *sc2;
|
|
246
|
|
247 //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
|
|
248
|
|
249 //static int count; if (++count == 20) *(char*)0=0;
|
|
250
|
|
251 assert(type);
|
|
252 if (!members) // if forward reference
|
|
253 return;
|
|
254
|
|
255 if (symtab)
|
|
256 { if (!scope)
|
|
257 return; // semantic() already completed
|
|
258 }
|
|
259 else
|
|
260 symtab = new DsymbolTable();
|
|
261
|
|
262 Scope *scx = NULL;
|
|
263 if (scope)
|
|
264 { sc = scope;
|
|
265 scx = scope; // save so we don't make redundant copies
|
|
266 scope = NULL;
|
|
267 }
|
|
268
|
|
269 parent = sc->parent;
|
|
270 type = type->semantic(loc, sc);
|
|
271 #if STRUCTTHISREF
|
|
272 handle = type;
|
|
273 #else
|
|
274 handle = type->pointerTo();
|
|
275 #endif
|
|
276 structalign = sc->structalign;
|
|
277 protection = sc->protection;
|
|
278 if (sc->stc & STCdeprecated)
|
|
279 isdeprecated = 1;
|
|
280 assert(!isAnonymous());
|
|
281 if (sc->stc & STCabstract)
|
|
282 error("structs, unions cannot be abstract");
|
|
283 #if DMDV2
|
|
284 if (storage_class & STCinvariant)
|
|
285 type = type->invariantOf();
|
|
286 else if (storage_class & STCconst)
|
|
287 type = type->constOf();
|
|
288 #endif
|
|
289
|
|
290 if (sizeok == 0) // if not already done the addMember step
|
|
291 {
|
|
292 for (i = 0; i < members->dim; i++)
|
|
293 {
|
|
294 Dsymbol *s = (Dsymbol *)members->data[i];
|
|
295 //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
|
|
296 s->addMember(sc, this, 1);
|
|
297 }
|
|
298 }
|
|
299
|
|
300 sizeok = 0;
|
|
301 sc2 = sc->push(this);
|
|
302 sc2->stc = 0;
|
|
303 sc2->parent = this;
|
|
304 if (isUnionDeclaration())
|
|
305 sc2->inunion = 1;
|
|
306 sc2->protection = PROTpublic;
|
|
307 sc2->explicitProtection = 0;
|
|
308
|
|
309 int members_dim = members->dim;
|
|
310 for (i = 0; i < members_dim; i++)
|
|
311 {
|
|
312 Dsymbol *s = (Dsymbol *)members->data[i];
|
|
313 s->semantic(sc2);
|
|
314 if (isUnionDeclaration())
|
|
315 sc2->offset = 0;
|
|
316 #if 0
|
|
317 if (sizeok == 2)
|
|
318 { //printf("forward reference\n");
|
|
319 break;
|
|
320 }
|
|
321 #endif
|
|
322 }
|
|
323
|
|
324 /* The TypeInfo_Struct is expecting an opEquals and opCmp with
|
|
325 * a parameter that is a pointer to the struct. But if there
|
|
326 * isn't one, but is an opEquals or opCmp with a value, write
|
|
327 * another that is a shell around the value:
|
|
328 * int opCmp(struct *p) { return opCmp(*p); }
|
|
329 */
|
|
330
|
|
331 TypeFunction *tfeqptr;
|
|
332 {
|
|
333 Arguments *arguments = new Arguments;
|
|
334 Argument *arg = new Argument(STCin, handle, Id::p, NULL);
|
|
335
|
|
336 arguments->push(arg);
|
|
337 tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
|
|
338 tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc);
|
|
339 }
|
|
340
|
|
341 TypeFunction *tfeq;
|
|
342 {
|
|
343 Arguments *arguments = new Arguments;
|
|
344 Argument *arg = new Argument(STCin, type, NULL, NULL);
|
|
345
|
|
346 arguments->push(arg);
|
|
347 tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
|
|
348 tfeq = (TypeFunction *)tfeq->semantic(0, sc);
|
|
349 }
|
|
350
|
|
351 Identifier *id = Id::eq;
|
|
352 for (int i = 0; i < 2; i++)
|
|
353 {
|
|
354 Dsymbol *s = search_function(this, id);
|
|
355 FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
|
|
356 if (fdx)
|
|
357 { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule());
|
|
358 if (!fd)
|
|
359 { fd = fdx->overloadExactMatch(tfeq, getModule());
|
|
360 if (fd)
|
|
361 { // Create the thunk, fdptr
|
|
362 FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
|
|
363 Expression *e = new IdentifierExp(loc, Id::p);
|
|
364 e = new PtrExp(loc, e);
|
|
365 Expressions *args = new Expressions();
|
|
366 args->push(e);
|
|
367 e = new IdentifierExp(loc, id);
|
|
368 e = new CallExp(loc, e, args);
|
|
369 fdptr->fbody = new ReturnStatement(loc, e);
|
|
370 ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
|
|
371 assert(s);
|
|
372 s->members->push(fdptr);
|
|
373 fdptr->addMember(sc, s, 1);
|
|
374 fdptr->semantic(sc2);
|
|
375 }
|
|
376 }
|
|
377 }
|
|
378
|
|
379 id = Id::cmp;
|
|
380 }
|
|
381 #if DMDV2
|
|
382 dtor = buildDtor(sc2);
|
|
383 postblit = buildPostBlit(sc2);
|
|
384 cpctor = buildCpCtor(sc2);
|
|
385 buildOpAssign(sc2);
|
|
386 #endif
|
|
387
|
|
388 sc2->pop();
|
|
389
|
|
390 if (sizeok == 2)
|
|
391 { // semantic() failed because of forward references.
|
|
392 // Unwind what we did, and defer it for later
|
|
393 fields.setDim(0);
|
|
394 structsize = 0;
|
|
395 alignsize = 0;
|
|
396 structalign = 0;
|
|
397
|
|
398 scope = scx ? scx : new Scope(*sc);
|
|
399 scope->setNoFree();
|
|
400 scope->module->addDeferredSemantic(this);
|
|
401 //printf("\tdeferring %s\n", toChars());
|
|
402 return;
|
|
403 }
|
|
404
|
|
405 // 0 sized struct's are set to 1 byte
|
|
406 if (structsize == 0)
|
|
407 {
|
|
408 structsize = 1;
|
|
409 alignsize = 1;
|
|
410 }
|
|
411
|
|
412 // Round struct size up to next alignsize boundary.
|
|
413 // This will ensure that arrays of structs will get their internals
|
|
414 // aligned properly.
|
|
415 structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
|
|
416
|
|
417 sizeok = 1;
|
|
418 Module::dprogress++;
|
|
419
|
|
420 //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
|
|
421
|
|
422 // Determine if struct is all zeros or not
|
|
423 zeroInit = 1;
|
|
424 for (i = 0; i < fields.dim; i++)
|
|
425 {
|
|
426 Dsymbol *s = (Dsymbol *)fields.data[i];
|
|
427 VarDeclaration *vd = s->isVarDeclaration();
|
|
428 if (vd && !vd->isDataseg())
|
|
429 {
|
|
430 if (vd->init)
|
|
431 {
|
|
432 // Should examine init to see if it is really all 0's
|
|
433 zeroInit = 0;
|
|
434 break;
|
|
435 }
|
|
436 else
|
|
437 {
|
|
438 if (!vd->type->isZeroInit(loc))
|
|
439 {
|
|
440 zeroInit = 0;
|
|
441 break;
|
|
442 }
|
|
443 }
|
|
444 }
|
|
445 }
|
|
446
|
|
447 /* Look for special member functions.
|
|
448 */
|
|
449 #if DMDV2
|
|
450 ctor = (CtorDeclaration *)search(0, Id::ctor, 0);
|
|
451 #endif
|
|
452 inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0);
|
|
453 aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
|
|
454 aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
|
|
455
|
|
456 if (sc->func)
|
|
457 {
|
|
458 semantic2(sc);
|
|
459 semantic3(sc);
|
|
460 }
|
|
461 }
|
|
462
|
|
463 void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
|
464 { int i;
|
|
465
|
|
466 buf->printf("%s ", kind());
|
|
467 if (!isAnonymous())
|
|
468 buf->writestring(toChars());
|
|
469 if (!members)
|
|
470 {
|
|
471 buf->writeByte(';');
|
|
472 buf->writenl();
|
|
473 return;
|
|
474 }
|
|
475 buf->writenl();
|
|
476 buf->writeByte('{');
|
|
477 buf->writenl();
|
|
478 for (i = 0; i < members->dim; i++)
|
|
479 {
|
|
480 Dsymbol *s = (Dsymbol *)members->data[i];
|
|
481
|
|
482 buf->writestring(" ");
|
|
483 s->toCBuffer(buf, hgs);
|
|
484 }
|
|
485 buf->writeByte('}');
|
|
486 buf->writenl();
|
|
487 }
|
|
488
|
|
489
|
|
490 const char *StructDeclaration::kind()
|
|
491 {
|
|
492 return "struct";
|
|
493 }
|
|
494
|
|
495 /********************************* UnionDeclaration ****************************/
|
|
496
|
|
497 UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
|
|
498 : StructDeclaration(loc, id)
|
|
499 {
|
|
500 }
|
|
501
|
|
502 Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
|
|
503 {
|
|
504 UnionDeclaration *ud;
|
|
505
|
|
506 if (s)
|
|
507 ud = (UnionDeclaration *)s;
|
|
508 else
|
|
509 ud = new UnionDeclaration(loc, ident);
|
|
510 StructDeclaration::syntaxCopy(ud);
|
|
511 return ud;
|
|
512 }
|
|
513
|
|
514
|
|
515 const char *UnionDeclaration::kind()
|
|
516 {
|
|
517 return "union";
|
|
518 }
|
|
519
|
|
520
|