Allow returning something of type void in a function that returns void
[delight/core.git] / dmd2 / struct.c
blob22ea0cc338ff98569bda02c624f6b004293ef2aa
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 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;
55 dtor = NULL;
58 enum PROT AggregateDeclaration::prot()
60 return protection;
63 void AggregateDeclaration::semantic2(Scope *sc)
65 //printf("AggregateDeclaration::semantic2(%s)\n", toChars());
66 if (scope)
67 { error("has forward references");
68 return;
70 if (members)
72 sc = sc->push(this);
73 for (size_t i = 0; i < members->dim; i++)
75 Dsymbol *s = (Dsymbol *)members->data[i];
76 s->semantic2(sc);
78 sc->pop();
82 void AggregateDeclaration::semantic3(Scope *sc)
83 { int i;
85 //printf("AggregateDeclaration::semantic3(%s)\n", toChars());
86 if (members)
88 sc = sc->push(this);
89 for (i = 0; i < members->dim; i++)
91 Dsymbol *s = (Dsymbol *)members->data[i];
92 s->semantic3(sc);
94 sc->pop();
98 void AggregateDeclaration::inlineScan()
99 { int i;
101 //printf("AggregateDeclaration::inlineScan(%s)\n", toChars());
102 if (members)
104 for (i = 0; i < members->dim; i++)
106 Dsymbol *s = (Dsymbol *)members->data[i];
107 //printf("inline scan aggregate symbol '%s'\n", s->toChars());
108 s->inlineScan();
113 target_size_t AggregateDeclaration::size(Loc loc)
115 //printf("AggregateDeclaration::size() = %d\n", structsize);
116 if (!members)
117 error(loc, "unknown size");
118 if (sizeok != 1)
119 { error(loc, "no size yet for forward reference");
120 //*(char*)0=0;
122 return structsize;
125 Type *AggregateDeclaration::getType()
127 return type;
130 int AggregateDeclaration::isDeprecated()
132 return isdeprecated;
135 /****************************
136 * Do byte or word alignment as necessary.
137 * Align sizes of 0, as we may not know array sizes yet.
140 void AggregateDeclaration::alignmember(target_size_t salign, target_size_t size, target_size_t *poffset)
142 //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset);
143 if (salign > 1)
144 { int sa;
146 switch (size)
147 { case 1:
148 break;
149 case 2:
150 case_2:
151 *poffset = (*poffset + 1) & ~1; // align to word
152 break;
153 case 3:
154 case 4:
155 if (salign == 2)
156 goto case_2;
157 *poffset = (*poffset + 3) & ~3; // align to dword
158 break;
159 default:
160 *poffset = (*poffset + salign - 1) & ~(salign - 1);
161 break;
164 //printf("result = %d\n",offset);
168 void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v)
170 target_size_t memsize; // size of member
171 target_size_t memalignsize; // size of member for alignment purposes
172 target_size_t xalign; // alignment boundaries
174 //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars());
175 assert(!(v->storage_class & (STCstatic | STCextern | STCparameter | STCtls)));
177 // Check for forward referenced types which will fail the size() call
178 Type *t = v->type->toBasetype();
179 if (t->ty == Tstruct /*&& isStructDeclaration()*/)
180 { TypeStruct *ts = (TypeStruct *)t;
182 if (ts->sym == this)
184 error("cannot have field %s with same struct type", v->toChars());
187 if (ts->sym->sizeok != 1)
189 sizeok = 2; // cannot finish; flag as forward referenced
190 return;
193 if (t->ty == Tident)
195 sizeok = 2; // cannot finish; flag as forward referenced
196 return;
199 memsize = v->type->size(loc);
200 memalignsize = v->type->alignsize();
201 xalign = v->type->memalign(sc->structalign);
202 alignmember(xalign, memalignsize, &sc->offset);
203 v->offset = sc->offset;
204 sc->offset += memsize;
205 if (sc->offset > structsize)
206 structsize = sc->offset;
207 if (sc->structalign < memalignsize)
208 memalignsize = sc->structalign;
209 if (alignsize < memalignsize)
210 alignsize = memalignsize;
211 //printf("\talignsize = %d\n", alignsize);
213 v->storage_class |= STCfield;
214 //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize);
215 fields.push(v);
219 /********************************* StructDeclaration ****************************/
221 StructDeclaration::StructDeclaration(Loc loc, Identifier *id)
222 : AggregateDeclaration(loc, id)
224 zeroInit = 0; // assume false until we do semantic processing
225 hasIdentityAssign = 0;
226 cpctor = NULL;
227 postblit = NULL;
229 // For forward references
230 type = new TypeStruct(this);
233 Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
235 StructDeclaration *sd;
237 if (s)
238 sd = (StructDeclaration *)s;
239 else
240 sd = new StructDeclaration(loc, ident);
241 ScopeDsymbol::syntaxCopy(sd);
242 return sd;
245 void StructDeclaration::semantic(Scope *sc)
246 { int i;
247 Scope *sc2;
249 //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
251 //static int count; if (++count == 20) *(char*)0=0;
253 assert(type);
254 if (!members) // if forward reference
255 return;
257 if (symtab)
258 { if (!scope)
259 return; // semantic() already completed
261 else
262 symtab = new DsymbolTable();
264 Scope *scx = NULL;
265 if (scope)
266 { sc = scope;
267 scx = scope; // save so we don't make redundant copies
268 scope = NULL;
270 #ifdef IN_GCC
271 methods.setDim(0);
272 #endif
274 parent = sc->parent;
275 handle = type->pointerTo();
276 structalign = sc->structalign;
277 protection = sc->protection;
278 storage_class |= sc->stc;
279 assert(!isAnonymous());
280 if (sc->stc & STCabstract)
281 error("structs, unions cannot be abstract");
282 if (storage_class & STCinvariant)
283 type = type->invariantOf();
284 else if (storage_class & STCconst)
285 type = type->constOf();
286 if (attributes)
287 attributes->append(sc->attributes);
288 else
289 attributes = sc->attributes;
291 if (sizeok == 0) // if not already done the addMember step
293 for (i = 0; i < members->dim; i++)
295 Dsymbol *s = (Dsymbol *)members->data[i];
296 //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
297 s->addMember(sc, this, 1);
301 sizeok = 0;
302 sc2 = sc->push(this);
303 sc2->stc &= storage_class & (STCconst | STCinvariant);
304 sc2->attributes = NULL;
305 sc2->parent = this;
306 if (isUnionDeclaration())
307 sc2->inunion = 1;
308 sc2->protection = PROTpublic;
309 sc2->explicitProtection = 0;
311 int members_dim = members->dim;
312 for (i = 0; i < members_dim; i++)
314 Dsymbol *s = (Dsymbol *)members->data[i];
315 s->semantic(sc2);
316 if (isUnionDeclaration())
317 sc2->offset = 0;
318 #if 0
319 if (sizeok == 2)
320 { //printf("forward reference\n");
321 break;
323 #endif
326 /* The TypeInfo_Struct is expecting an opEquals and opCmp with
327 * a parameter that is a pointer to the struct. But if there
328 * isn't one, but is an opEquals or opCmp with a value, write
329 * another that is a shell around the value:
330 * int opCmp(struct *p) { return opCmp(*p); }
333 TypeFunction *tfeqptr;
335 Arguments *arguments = new Arguments;
336 Argument *arg = new Argument(STCin, handle, Id::p, NULL);
338 arguments->push(arg);
339 tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
340 tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc);
343 TypeFunction *tfeq;
345 Arguments *arguments = new Arguments;
346 Argument *arg = new Argument(STCin, type, NULL, NULL);
348 arguments->push(arg);
349 tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
350 tfeq = (TypeFunction *)tfeq->semantic(0, sc);
353 Identifier *id = Id::eq;
354 for (int i = 0; i < 2; i++)
356 Dsymbol *s = search_function(this, id);
357 FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
358 if (fdx)
359 { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
360 if (!fd)
361 { fd = fdx->overloadExactMatch(tfeq);
362 if (fd)
363 { // Create the thunk, fdptr
364 FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
365 Expression *e = new IdentifierExp(loc, Id::p);
366 e = new PtrExp(loc, e);
367 Expressions *args = new Expressions();
368 args->push(e);
369 e = new IdentifierExp(loc, id);
370 e = new CallExp(loc, e, args);
371 fdptr->fbody = new ReturnStatement(loc, e);
372 ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
373 assert(s);
374 s->members->push(fdptr);
375 fdptr->addMember(sc, s, 1);
376 fdptr->semantic(sc2);
381 id = Id::cmp;
384 dtor = buildDtor(sc2);
385 postblit = buildPostBlit(sc2);
386 cpctor = buildCpCtor(sc2);
387 buildOpAssign(sc2);
389 sc2->pop();
391 if (sizeok == 2)
392 { // semantic() failed because of forward references.
393 // Unwind what we did, and defer it for later
394 fields.setDim(0);
395 structsize = 0;
396 alignsize = 0;
397 structalign = 0;
399 scope = scx ? scx : new Scope(*sc);
400 scope->setNoFree();
401 scope->module->addDeferredSemantic(this);
402 //printf("\tdeferring %s\n", toChars());
403 return;
406 // 0 sized struct's are set to 1 byte
407 if (structsize == 0)
409 structsize = 1;
410 alignsize = 1;
413 // Round struct size up to next alignsize boundary.
414 // This will ensure that arrays of structs will get their internals
415 // aligned properly.
416 structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
418 sizeok = 1;
419 Module::dprogress++;
421 //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
423 // Determine if struct is all zeros or not
424 zeroInit = 1;
425 for (i = 0; i < fields.dim; i++)
427 Dsymbol *s = (Dsymbol *)fields.data[i];
428 VarDeclaration *vd = s->isVarDeclaration();
429 if (vd && !vd->isDataseg())
431 if (vd->init)
433 // Should examine init to see if it is really all 0's
434 zeroInit = 0;
435 break;
437 else
439 if (!vd->type->isZeroInit())
441 zeroInit = 0;
442 break;
448 /* Look for special member functions.
450 inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0);
451 aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
452 aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
454 if (sc->func)
456 semantic2(sc);
457 semantic3(sc);
461 void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
462 { int i;
464 buf->printf("%s ", kind());
465 if (!isAnonymous())
466 buf->writestring(toChars());
467 if (!members)
469 buf->writeByte(';');
470 buf->writenl();
471 return;
473 buf->writenl();
474 buf->writeByte('{');
475 buf->writenl();
476 for (i = 0; i < members->dim; i++)
478 Dsymbol *s = (Dsymbol *)members->data[i];
480 buf->writestring(" ");
481 s->toCBuffer(buf, hgs);
483 buf->writeByte('}');
484 buf->writenl();
488 char *StructDeclaration::kind()
490 return "struct";
493 /********************************* UnionDeclaration ****************************/
495 UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
496 : StructDeclaration(loc, id)
500 Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
502 UnionDeclaration *ud;
504 if (s)
505 ud = (UnionDeclaration *)s;
506 else
507 ud = new UnionDeclaration(loc, ident);
508 StructDeclaration::syntaxCopy(ud);
509 return ud;
513 char *UnionDeclaration::kind()
515 return "union";