Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
653 lines (568 sloc) 17.2 KB
// Compiler implementation of the D programming language
// Copyright (c) 1999-2012 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <assert.h>
#include "root.h"
#include "aggregate.h"
#include "scope.h"
#include "mtype.h"
#include "declaration.h"
#include "module.h"
#include "id.h"
#include "statement.h"
#include "template.h"
/********************************* AggregateDeclaration ****************************/
AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
: ScopeDsymbol(id)
{
this->loc = loc;
storage_class = 0;
protection = PROTpublic;
type = NULL;
handle = NULL;
structsize = 0; // size of struct
alignsize = 0; // size of struct for alignment purposes
structalign = 0; // struct member alignment in effect
hasUnions = 0;
sizeok = SIZEOKnone; // size not determined yet
isdeprecated = 0;
inv = NULL;
aggNew = NULL;
aggDelete = NULL;
#if IN_DMD
stag = NULL;
sinit = NULL;
#endif
#if DMDV2
dtor = NULL;
ctor = NULL;
defaultCtor = NULL;
aliasthis = NULL;
noDefaultCtor = FALSE;
#endif
dtor = NULL;
#if IN_LLVM
availableExternally = true; // assume this unless proven otherwise
#endif
}
enum PROT AggregateDeclaration::prot()
{
return protection;
}
void AggregateDeclaration::semantic2(Scope *sc)
{
//printf("AggregateDeclaration::semantic2(%s)\n", toChars());
if (scope && members)
{ error("has forward references");
return;
}
if (members)
{
sc = sc->push(this);
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = members->tdata()[i];
s->semantic2(sc);
}
sc->pop();
}
}
void AggregateDeclaration::semantic3(Scope *sc)
{
// LDC
if (!global.params.useAvailableExternally)
availableExternally = false;
//printf("AggregateDeclaration::semantic3(%s)\n", toChars());
if (members)
{
sc = sc->push(this);
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = members->tdata()[i];
s->semantic3(sc);
}
sc->pop();
}
}
void AggregateDeclaration::inlineScan()
{
//printf("AggregateDeclaration::inlineScan(%s)\n", toChars());
if (members)
{
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = members->tdata()[i];
//printf("inline scan aggregate symbol '%s'\n", s->toChars());
s->inlineScan();
}
}
}
unsigned AggregateDeclaration::size(Loc loc)
{
//printf("AggregateDeclaration::size() = %d\n", structsize);
if (!members)
error(loc, "unknown size");
if (sizeok != SIZEOKdone && scope)
semantic(NULL);
if (sizeok != SIZEOKdone)
{ error(loc, "no size yet for forward reference");
//*(char*)0=0;
}
return structsize;
}
Type *AggregateDeclaration::getType()
{
return type;
}
int AggregateDeclaration::isDeprecated()
{
return isdeprecated;
}
int AggregateDeclaration::isExport()
{
return protection == PROTexport;
}
/****************************
* Do byte or word alignment as necessary.
* Align sizes of 0, as we may not know array sizes yet.
*/
void AggregateDeclaration::alignmember(
unsigned salign, // struct alignment that is in effect
unsigned size, // alignment requirement of field
unsigned *poffset)
{
//printf("salign = %d, size = %d, offset = %d\n",salign,size, *poffset);
if (salign > 1)
{
assert(size != 3);
unsigned sa = size;
if (sa == 0 || salign < sa)
sa = salign;
*poffset = (*poffset + sa - 1) & ~(sa - 1);
}
//printf("result = %d\n", *poffset);
}
/****************************************
* Place a member (mem) into an aggregate (agg), which can be a struct, union or class
* Returns:
* offset to place field at
*/
unsigned AggregateDeclaration::placeField(
unsigned *nextoffset, // next location in aggregate
unsigned memsize, // size of member
unsigned memalignsize, // size of member for alignment purposes
unsigned memalign, // alignment in effect for this member
unsigned *paggsize, // size of aggregate (updated)
unsigned *paggalignsize, // size of aggregate for alignment purposes (updated)
bool isunion // the aggregate is a union
)
{
unsigned ofs = *nextoffset;
alignmember(memalign, memalignsize, &ofs);
unsigned memoffset = ofs;
ofs += memsize;
if (ofs > *paggsize)
*paggsize = ofs;
if (!isunion)
*nextoffset = ofs;
if (global.params.is64bit && memalign == 8 && memalignsize == 16)
/* Not sure how to handle this */
;
else if (memalign < memalignsize)
memalignsize = memalign;
if (*paggalignsize < memalignsize)
*paggalignsize = memalignsize;
return memoffset;
}
/****************************************
* If field[indx] is not part of a union, return indx.
* Otherwise, return the lowest field index of the union.
*/
int AggregateDeclaration::firstFieldInUnion(int indx)
{
if (isUnionDeclaration())
return 0;
VarDeclaration * vd = fields.tdata()[indx];
int firstNonZero = indx; // first index in the union with non-zero size
for (; ;)
{
if (indx == 0)
return firstNonZero;
VarDeclaration * v = fields.tdata()[indx - 1];
if (v->offset != vd->offset)
return firstNonZero;
--indx;
/* If it is a zero-length field, it's ambiguous: we don't know if it is
* in the union unless we find an earlier non-zero sized field with the
* same offset.
*/
if (v->size(loc) != 0)
firstNonZero = indx;
}
}
/****************************************
* Count the number of fields starting at firstIndex which are part of the
* same union as field[firstIndex]. If not a union, return 1.
*/
int AggregateDeclaration::numFieldsInUnion(int firstIndex)
{
VarDeclaration * vd = fields.tdata()[firstIndex];
/* If it is a zero-length field, AND we can't find an earlier non-zero
* sized field with the same offset, we assume it's not part of a union.
*/
if (vd->size(loc) == 0 && !isUnionDeclaration() &&
firstFieldInUnion(firstIndex) == firstIndex)
return 1;
int count = 1;
for (size_t i = firstIndex+1; i < fields.dim; ++i)
{
VarDeclaration * v = fields.tdata()[i];
// If offsets are different, they are not in the same union
if (v->offset != vd->offset)
break;
++count;
}
return count;
}
/********************************* StructDeclaration ****************************/
StructDeclaration::StructDeclaration(Loc loc, Identifier *id)
: AggregateDeclaration(loc, id)
{
zeroInit = 0; // assume false until we do semantic processing
#if DMDV2
hasIdentityAssign = 0;
cpctor = NULL;
postblit = NULL;
eq = NULL;
#endif
// For forward references
type = new TypeStruct(this);
}
Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
{
StructDeclaration *sd;
if (s)
sd = (StructDeclaration *)s;
else
sd = new StructDeclaration(loc, ident);
ScopeDsymbol::syntaxCopy(sd);
return sd;
}
void StructDeclaration::semantic(Scope *sc)
{
Scope *sc2;
//printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toChars(), sizeok);
//static int count; if (++count == 20) halt();
assert(type);
if (!members) // if forward reference
return;
if (symtab)
{ if (sizeok == SIZEOKdone || !scope)
{ //printf("already completed\n");
scope = NULL;
return; // semantic() already completed
}
}
else
symtab = new DsymbolTable();
Scope *scx = NULL;
if (scope)
{ sc = scope;
scx = scope; // save so we don't make redundant copies
scope = NULL;
}
unsigned dprogress_save = Module::dprogress;
parent = sc->parent;
type = type->semantic(loc, sc);
#if STRUCTTHISREF
handle = type;
#else
handle = type->pointerTo();
#endif
structalign = sc->structalign;
protection = sc->protection;
if (sc->stc & STCdeprecated)
isdeprecated = 1;
assert(!isAnonymous());
if (sc->stc & STCabstract)
error("structs, unions cannot be abstract");
#if DMDV2
if (storage_class & STCimmutable)
type = type->invariantOf();
else if (storage_class & STCconst)
type = type->constOf();
#endif
if (sizeok == SIZEOKnone) // if not already done the addMember step
{
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = members->tdata()[i];
//printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
s->addMember(sc, this, 1);
}
}
sizeok = SIZEOKnone;
sc2 = sc->push(this);
sc2->stc = 0;
sc2->parent = this;
if (isUnionDeclaration())
sc2->inunion = 1;
sc2->protection = PROTpublic;
sc2->explicitProtection = 0;
size_t members_dim = members->dim;
/* Set scope so if there are forward references, we still might be able to
* resolve individual members like enums.
*/
for (size_t i = 0; i < members_dim; i++)
{ Dsymbol *s = (*members)[i];
/* There are problems doing this in the general case because
* Scope keeps track of things like 'offset'
*/
if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident))
{
//printf("setScope %s %s\n", s->kind(), s->toChars());
s->setScope(sc2);
}
}
for (size_t i = 0; i < members_dim; i++)
{
Dsymbol *s = (*members)[i];
// Ungag errors when not speculative
unsigned oldgag = global.gag;
if (global.isSpeculativeGagging() && !isSpeculative())
global.gag = 0;
s->semantic(sc2);
global.gag = oldgag;
#if 0
if (sizeok == 2)
{ //printf("forward reference\n");
break;
}
#endif
}
finalizeSize(sc2);
#if DMDV1
/* This doesn't work for DMDV2 because (ref S) and (S) parameter
* lists will overload the same.
*/
/* The TypeInfo_Struct is expecting an opEquals and opCmp with
* a parameter that is a pointer to the struct. But if there
* isn't one, but is an opEquals or opCmp with a value, write
* another that is a shell around the value:
* int opCmp(struct *p) { return opCmp(*p); }
*/
TypeFunction *tfeqptr;
{
Parameters *arguments = new Parameters;
Parameter *arg = new Parameter(STCin, handle, Id::p, NULL);
arguments->push(arg);
tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc);
}
TypeFunction *tfeq;
{
Parameters *arguments = new Parameters;
Parameter *arg = new Parameter(STCin, type, NULL, NULL);
arguments->push(arg);
tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
tfeq = (TypeFunction *)tfeq->semantic(0, sc);
}
Identifier *id = Id::eq;
for (int i = 0; i < 2; i++)
{
Dsymbol *s = search_function(this, id);
FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
if (fdx)
{ FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule());
if (!fd)
{ fd = fdx->overloadExactMatch(tfeq, getModule());
if (fd)
{ // Create the thunk, fdptr
FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
Expression *e = new IdentifierExp(loc, Id::p);
e = new PtrExp(loc, e);
Expressions *args = new Expressions();
args->push(e);
e = new IdentifierExp(loc, id);
e = new CallExp(loc, e, args);
fdptr->fbody = new ReturnStatement(loc, e);
ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
assert(s);
s->members->push(fdptr);
fdptr->addMember(sc, s, 1);
fdptr->semantic(sc2);
}
}
}
id = Id::cmp;
}
#endif
#if DMDV2
dtor = buildDtor(sc2);
postblit = buildPostBlit(sc2);
cpctor = buildCpCtor(sc2);
buildOpAssign(sc2);
hasIdentityEquals = (buildOpEquals(sc2) != NULL);
xeq = buildXopEquals(sc2);
#endif
sc2->pop();
if (sizeok == 2)
{ // semantic() failed because of forward references.
// Unwind what we did, and defer it for later
for (size_t i = 0; i < fields.dim; i++)
{ Dsymbol *s = fields[i];
VarDeclaration *vd = s->isVarDeclaration();
if (vd)
vd->offset = 0;
}
fields.setDim(0);
structsize = 0;
alignsize = 0;
structalign = 0;
scope = scx ? scx : new Scope(*sc);
scope->setNoFree();
scope->module->addDeferredSemantic(this);
Module::dprogress = dprogress_save;
//printf("\tdeferring %s\n", toChars());
return;
}
// 0 sized struct's are set to 1 byte
if (structsize == 0)
{
structsize = 1;
alignsize = 1;
}
// Round struct size up to next alignsize boundary.
// This will ensure that arrays of structs will get their internals
// aligned properly.
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
sizeok = SIZEOKdone;
Module::dprogress++;
//printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
// Determine if struct is all zeros or not
zeroInit = 1;
for (size_t i = 0; i < fields.dim; i++)
{
Dsymbol *s = (Dsymbol *)fields.data[i];
VarDeclaration *vd = s->isVarDeclaration();
if (vd && !vd->isDataseg())
{
if (vd->init)
{
// Should examine init to see if it is really all 0's
zeroInit = 0;
break;
}
else
{
if (!vd->type->isZeroInit(loc))
{
zeroInit = 0;
break;
}
}
}
}
/* Look for special member functions.
*/
#if DMDV2
ctor = (CtorDeclaration *)search(0, Id::ctor, 0);
#endif
inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0);
aggNew = (NewDeclaration *)search(0, Id::classNew, 0);
aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0);
if (sc->func)
{
semantic2(sc);
semantic3(sc);
}
}
Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags)
{
//printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars());
if (scope && !symtab)
semantic(scope);
if (!members || !symtab)
{
error("is forward referenced when looking for '%s'", ident->toChars());
return NULL;
}
return ScopeDsymbol::search(loc, ident, flags);
}
void StructDeclaration::finalizeSize(Scope *sc)
{
if (sizeok != SIZEOKnone)
return;
// Set the offsets of the fields and determine the size of the struct
unsigned offset = 0;
bool isunion = isUnionDeclaration() != NULL;
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = (*members)[i];
s->setFieldOffset(this, &offset, isunion);
}
if (sizeok == SIZEOKfwd)
return;
// 0 sized struct's are set to 1 byte
if (structsize == 0)
{
structsize = 1;
alignsize = 1;
}
// Round struct size up to next alignsize boundary.
// This will ensure that arrays of structs will get their internals
// aligned properly.
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
sizeok = SIZEOKdone;
}
void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->printf("%s ", kind());
if (!isAnonymous())
buf->writestring(toChars());
if (!members)
{
buf->writeByte(';');
buf->writenl();
return;
}
buf->writenl();
buf->writeByte('{');
buf->writenl();
for (size_t i = 0; i < members->dim; i++)
{
Dsymbol *s = members->tdata()[i];
buf->writestring(" ");
s->toCBuffer(buf, hgs);
}
buf->writeByte('}');
buf->writenl();
}
const char *StructDeclaration::kind()
{
return "struct";
}
/********************************* UnionDeclaration ****************************/
UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
: StructDeclaration(loc, id)
{
}
Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
{
UnionDeclaration *ud;
if (s)
ud = (UnionDeclaration *)s;
else
ud = new UnionDeclaration(loc, ident);
StructDeclaration::syntaxCopy(ud);
return ud;
}
const char *UnionDeclaration::kind()
{
return "union";
}
Jump to Line
Something went wrong with that request. Please try again.