The expression "x in dict" is now a maybe type
[delight/core.git] / dmd / struct.c
blobc833eb0619797622eda2caa89eb189de7547cf45
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.
11 /* NOTE: This file has been patched from the original DMD distribution to
12 work with the GDC compiler.
14 Modified by David Friedman, December 2006
17 #include <stdio.h>
18 #include <assert.h>
20 #include "root.h"
21 #include "aggregate.h"
22 #include "scope.h"
23 #include "mtype.h"
24 #include "declaration.h"
25 #include "module.h"
26 #include "id.h"
27 #include "statement.h"
29 /********************************* AggregateDeclaration ****************************/
31 AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
32 : ScopeDsymbol(id)
34 this->loc = loc;
36 storage_class = 0;
37 protection = PROTpublic;
38 type = NULL;
39 handle = NULL;
40 structsize = 0; // size of struct
41 alignsize = 0; // size of struct for alignment purposes
42 structalign = 0; // struct member alignment in effect
43 hasUnions = 0;
44 sizeok = 0; // size not determined yet
45 isdeprecated = 0;
46 inv = NULL;
47 aggNew = NULL;
48 aggDelete = NULL;
50 attributes = NULL;
52 stag = NULL;
53 sinit = NULL;
54 scope = NULL;
57 enum PROT AggregateDeclaration::prot()
59 return protection;
62 void AggregateDeclaration::semantic2(Scope *sc)
64 //printf("AggregateDeclaration::semantic2(%s)\n", toChars());
65 if (scope)
66 { error("has forward references");
67 return;
69 if (members)
71 sc = sc->push(this);
72 for (size_t i = 0; i < members->dim; i++)
74 Dsymbol *s = (Dsymbol *)members->data[i];
75 s->semantic2(sc);
77 sc->pop();
81 void AggregateDeclaration::semantic3(Scope *sc)
82 { int i;
84 //printf("AggregateDeclaration::semantic3(%s)\n", toChars());
85 if (members)
87 sc = sc->push(this);
88 for (i = 0; i < members->dim; i++)
90 Dsymbol *s = (Dsymbol *)members->data[i];
91 s->semantic3(sc);
93 sc->pop();
97 void AggregateDeclaration::inlineScan()
98 { int i;
100 //printf("AggregateDeclaration::inlineScan(%s)\n", toChars());
101 if (members)
103 for (i = 0; i < members->dim; i++)
105 Dsymbol *s = (Dsymbol *)members->data[i];
106 //printf("inline scan aggregate symbol '%s'\n", s->toChars());
107 s->inlineScan();
112 target_size_t AggregateDeclaration::size(Loc loc)
114 //printf("AggregateDeclaration::size() = %d\n", structsize);
115 if (!members)
116 error(loc, "unknown size");
117 if (sizeok != 1)
118 { error(loc, "no size yet for forward reference");
119 //*(char*)0=0;
121 return structsize;
124 Type *AggregateDeclaration::getType()
126 return type;
129 int AggregateDeclaration::isDeprecated()
131 return isdeprecated;
134 /****************************
135 * Do byte or word alignment as necessary.
136 * Align sizes of 0, as we may not know array sizes yet.
139 void AggregateDeclaration::alignmember(target_size_t salign, target_size_t size, target_size_t *poffset)
141 //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset);
142 if (salign > 1)
143 { int sa;
145 switch (size)
146 { case 1:
147 break;
148 case 2:
149 case_2:
150 *poffset = (*poffset + 1) & ~1; // align to word
151 break;
152 case 3:
153 case 4:
154 if (salign == 2)
155 goto case_2;
156 *poffset = (*poffset + 3) & ~3; // align to dword
157 break;
158 default:
159 *poffset = (*poffset + salign - 1) & ~(salign - 1);
160 break;
163 //printf("result = %d\n",offset);
167 void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v)
169 target_size_t memsize; // size of member
170 target_size_t memalignsize; // size of member for alignment purposes
171 target_size_t xalign; // alignment boundaries
173 //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars());
175 // Check for forward referenced types which will fail the size() call
176 Type *t = v->type->toBasetype();
177 if (t->ty == Tstruct /*&& isStructDeclaration()*/)
178 { TypeStruct *ts = (TypeStruct *)t;
180 if (ts->sym->sizeok != 1)
182 sizeok = 2; // cannot finish; flag as forward referenced
183 return;
186 if (t->ty == Tident)
188 sizeok = 2; // cannot finish; flag as forward referenced
189 return;
192 memsize = v->type->size(loc);
193 memalignsize = v->type->alignsize();
194 xalign = v->type->memalign(sc->structalign);
195 alignmember(xalign, memalignsize, &sc->offset);
196 v->offset = sc->offset;
197 sc->offset += memsize;
198 if (sc->offset > structsize)
199 structsize = sc->offset;
200 if (sc->structalign < memalignsize)
201 memalignsize = sc->structalign;
202 if (alignsize < memalignsize)
203 alignsize = memalignsize;
204 //printf("\talignsize = %d\n", alignsize);
206 v->storage_class |= STCfield;
207 //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize);
208 fields.push(v);
212 /********************************* StructDeclaration ****************************/
214 StructDeclaration::StructDeclaration(Loc loc, Identifier *id)
215 : AggregateDeclaration(loc, id)
217 zeroInit = 0; // assume false until we do semantic processing
219 // For forward references
220 type = new TypeStruct(this);
223 Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
225 StructDeclaration *sd;
227 if (s)
228 sd = (StructDeclaration *)s;
229 else
230 sd = new StructDeclaration(loc, ident);
231 ScopeDsymbol::syntaxCopy(sd);
232 return sd;
235 void StructDeclaration::semantic(Scope *sc)
236 { int i;
237 Scope *sc2;
239 //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
241 //static int count; if (++count == 20) *(char*)0=0;
243 assert(type);
244 if (!members) // if forward reference
245 return;
247 if (symtab)
248 { if (!scope)
249 return; // semantic() already completed
251 else
252 symtab = new DsymbolTable();
254 Scope *scx = NULL;
255 if (scope)
256 { sc = scope;
257 scx = scope; // save so we don't make redundant copies
258 scope = NULL;
260 #ifdef IN_GCC
261 methods.setDim(0);
262 #endif
264 parent = sc->parent;
265 handle = type->pointerTo();
266 structalign = sc->structalign;
267 protection = sc->protection;
268 assert(!isAnonymous());
269 if (sc->stc & STCabstract)
270 error("structs, unions cannot be abstract");
271 if (attributes)
272 attributes->append(sc->attributes);
273 else
274 attributes = sc->attributes;
276 if (sizeok == 0) // if not already done the addMember step
278 for (i = 0; i < members->dim; i++)
280 Dsymbol *s = (Dsymbol *)members->data[i];
281 //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
282 s->addMember(sc, this, 1);
286 sizeok = 0;
287 sc2 = sc->push(this);
288 sc2->stc = 0;
289 sc2->attributes = NULL;
290 sc2->parent = this;
291 if (isUnionDeclaration())
292 sc2->inunion = 1;
293 sc2->protection = PROTpublic;
294 sc2->explicitProtection = 0;
296 int members_dim = members->dim;
297 for (i = 0; i < members_dim; i++)
299 Dsymbol *s = (Dsymbol *)members->data[i];
300 s->semantic(sc2);
301 if (isUnionDeclaration())
302 sc2->offset = 0;
303 #if 0
304 if (sizeok == 2)
305 { //printf("forward reference\n");
306 break;
308 #endif
311 /* The TypeInfo_Struct is expecting an opEquals and opCmp with
312 * a parameter that is a pointer to the struct. But if there
313 * isn't one, but is an opEquals or opCmp with a value, write
314 * another that is a shell around the value:
315 * int opCmp(struct *p) { return opCmp(*p); }
318 TypeFunction *tfeqptr;
320 Arguments *arguments = new Arguments;
321 Argument *arg = new Argument(STCin, handle, Id::p, NULL);
323 arguments->push(arg);
324 tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
325 tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc);
328 TypeFunction *tfeq;
330 Arguments *arguments = new Arguments;
331 Argument *arg = new Argument(STCin, type, NULL, NULL);
333 arguments->push(arg);
334 tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
335 tfeq = (TypeFunction *)tfeq->semantic(0, sc);
338 Identifier *id = Id::eq;
339 for (int i = 0; i < 2; i++)
341 Dsymbol *s = search_function(this, id);
342 FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
343 if (fdx)
344 { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
345 if (!fd)
346 { fd = fdx->overloadExactMatch(tfeq);
347 if (fd)
348 { // Create the thunk, fdptr
349 FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
350 Expression *e = new IdentifierExp(loc, Id::p);
351 e = new PtrExp(loc, e);
352 Expressions *args = new Expressions();
353 args->push(e);
354 e = new IdentifierExp(loc, id);
355 e = new CallExp(loc, e, args);
356 fdptr->fbody = new ReturnStatement(loc, e);
357 ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
358 assert(s);
359 s->members->push(fdptr);
360 fdptr->addMember(sc, s, 1);
361 fdptr->semantic(sc2);
366 id = Id::cmp;
370 sc2->pop();
372 if (sizeok == 2)
373 { // semantic() failed because of forward references.
374 // Unwind what we did, and defer it for later
375 fields.setDim(0);
376 structsize = 0;
377 alignsize = 0;
378 structalign = 0;
380 scope = scx ? scx : new Scope(*sc);
381 scope->setNoFree();
382 scope->module->addDeferredSemantic(this);
383 //printf("\tdeferring %s\n", toChars());
384 return;
387 // 0 sized struct's are set to 1 byte
388 if (structsize == 0)
390 structsize = 1;
391 alignsize = 1;
394 // Round struct size up to next alignsize boundary.
395 // This will ensure that arrays of structs will get their internals
396 // aligned properly.
397 structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
399 sizeok = 1;
400 Module::dprogress++;
402 //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
404 // Determine if struct is all zeros or not
405 zeroInit = 1;
406 for (i = 0; i < fields.dim; i++)
408 Dsymbol *s = (Dsymbol *)fields.data[i];
409 VarDeclaration *vd = s->isVarDeclaration();
410 if (vd && !vd->isDataseg())
412 if (vd->init)
414 // Should examine init to see if it is really all 0's
415 zeroInit = 0;
416 break;
418 else
420 if (!vd->type->isZeroInit())
422 zeroInit = 0;
423 break;
429 /* Look for special member functions.
431 inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0);
432 aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
433 aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
435 if (sc->func)
437 semantic2(sc);
438 semantic3(sc);
442 void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
443 { int i;
445 buf->printf("%s ", kind());
446 if (!isAnonymous())
447 buf->writestring(toChars());
448 if (!members)
450 buf->writeByte(';');
451 buf->writenl();
452 return;
454 buf->writenl();
455 buf->writeByte('{');
456 buf->writenl();
457 for (i = 0; i < members->dim; i++)
459 Dsymbol *s = (Dsymbol *)members->data[i];
461 buf->writestring(" ");
462 s->toCBuffer(buf, hgs);
464 buf->writeByte('}');
465 buf->writenl();
469 char *StructDeclaration::kind()
471 return "struct";
474 /********************************* UnionDeclaration ****************************/
476 UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
477 : StructDeclaration(loc, id)
481 Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
483 UnionDeclaration *ud;
485 if (s)
486 ud = (UnionDeclaration *)s;
487 else
488 ud = new UnionDeclaration(loc, ident);
489 StructDeclaration::syntaxCopy(ud);
490 return ud;
494 char *UnionDeclaration::kind()
496 return "union";