comparison dmd/struct.c @ 1:c53b6e3fe49a trunk

[svn r5] Initial commit. Most things are very rough.
author lindquist
date Sat, 01 Sep 2007 21:43:27 +0200
parents
children 28e99b04a132
comparison
equal deleted inserted replaced
0:a9e71648e74d 1:c53b6e3fe49a
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