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