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