Mercurial > projects > ldc
view dmd/declaration.c @ 1650:40bd4a0d4870
Update to work with LLVM 2.7.
Removed use of dyn_cast, llvm no compiles
without exceptions and rtti by
default. We do need exceptions for the libconfig stuff, but rtti isn't
necessary (anymore).
Debug info needs to be rewritten, as in LLVM 2.7 the format has
completely changed. To have something to look at while rewriting, the
old code has been wrapped inside #ifndef DISABLE_DEBUG_INFO , this means
that you have to define this to compile at the moment.
Updated tango 0.99.9 patch to include updated EH runtime code, which is
needed for LLVM 2.7 as well.
author | Tomas Lindquist Olsen |
---|---|
date | Wed, 19 May 2010 12:42:32 +0200 |
parents | 44b145be2ef5 |
children |
line wrap: on
line source
// Compiler implementation of the D programming language // Copyright (c) 1999-2009 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 "init.h" #include "declaration.h" #include "attrib.h" #include "mtype.h" #include "template.h" #include "scope.h" #include "aggregate.h" #include "module.h" #include "id.h" #include "expression.h" #include "hdrgen.h" /********************************* Declaration ****************************/ Declaration::Declaration(Identifier *id) : Dsymbol(id) { type = NULL; originalType = NULL; storage_class = STCundefined; protection = PROTundefined; linkage = LINKdefault; inuse = 0; } void Declaration::semantic(Scope *sc) { } const char *Declaration::kind() { return "declaration"; } unsigned Declaration::size(Loc loc) { assert(type); return type->size(); } int Declaration::isStaticConstructor() { return FALSE; } int Declaration::isStaticDestructor() { return FALSE; } int Declaration::isDelete() { return FALSE; } int Declaration::isDataseg() { return FALSE; } int Declaration::isThreadlocal() { return FALSE; } int Declaration::isCodeseg() { return FALSE; } enum PROT Declaration::prot() { return protection; } /************************************* * Check to see if declaration can be modified in this context (sc). * Issue error if not. */ #if DMDV2 void Declaration::checkModify(Loc loc, Scope *sc, Type *t) { if (sc->incontract && isParameter()) error(loc, "cannot modify parameter '%s' in contract", toChars()); if (isCtorinit()) { // It's only modifiable if inside the right constructor Dsymbol *s = sc->func; while (1) { FuncDeclaration *fd = NULL; if (s) fd = s->isFuncDeclaration(); if (fd && ((fd->isCtorDeclaration() && storage_class & STCfield) || (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && fd->toParent() == toParent() ) { VarDeclaration *v = isVarDeclaration(); assert(v); v->ctorinit = 1; //printf("setting ctorinit\n"); } else { if (s) { s = s->toParent2(); continue; } else { const char *p = isStatic() ? "static " : ""; error(loc, "can only initialize %sconst %s inside %sconstructor", p, toChars(), p); } } break; } } else { VarDeclaration *v = isVarDeclaration(); if (v && v->canassign == 0) { const char *p = NULL; if (isConst()) p = "const"; else if (isImmutable()) p = "immutable"; else if (storage_class & STCmanifest) p = "enum"; else if (!t->isAssignable()) p = "struct with immutable members"; if (p) { error(loc, "cannot modify %s", p); } } } } #endif /********************************* TupleDeclaration ****************************/ TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) : Declaration(id) { this->type = NULL; this->objects = objects; this->isexp = 0; this->tupletype = NULL; } Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) { assert(0); return NULL; } const char *TupleDeclaration::kind() { return "tuple"; } Type *TupleDeclaration::getType() { /* If this tuple represents a type, return that type */ //printf("TupleDeclaration::getType() %s\n", toChars()); if (isexp) return NULL; if (!tupletype) { /* It's only a type tuple if all the Object's are types */ for (size_t i = 0; i < objects->dim; i++) { Object *o = (Object *)objects->data[i]; if (o->dyncast() != DYNCAST_TYPE) { //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); return NULL; } } /* We know it's a type tuple, so build the TypeTuple */ Parameters *args = new Parameters(); args->setDim(objects->dim); OutBuffer buf; int hasdeco = 1; for (size_t i = 0; i < objects->dim; i++) { Type *t = (Type *)objects->data[i]; //printf("type = %s\n", t->toChars()); #if 0 buf.printf("_%s_%d", ident->toChars(), i); char *name = (char *)buf.extractData(); Identifier *id = new Identifier(name, TOKidentifier); Parameter *arg = new Parameter(STCin, t, id, NULL); #else Parameter *arg = new Parameter(STCin, t, NULL, NULL); #endif args->data[i] = (void *)arg; if (!t->deco) hasdeco = 0; } tupletype = new TypeTuple(args); if (hasdeco) return tupletype->semantic(0, NULL); } return tupletype; } int TupleDeclaration::needThis() { //printf("TupleDeclaration::needThis(%s)\n", toChars()); for (size_t i = 0; i < objects->dim; i++) { Object *o = (Object *)objects->data[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; if (e->op == TOKdsymbol) { DsymbolExp *ve = (DsymbolExp *)e; Declaration *d = ve->s->isDeclaration(); if (d && d->needThis()) { return 1; } } } } return 0; } /********************************* TypedefDeclaration ****************************/ TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) : Declaration(id) { this->type = new TypeTypedef(this); this->basetype = basetype->toBasetype(); this->init = init; #ifdef _DH this->htype = NULL; this->hbasetype = NULL; #endif this->sem = 0; this->loc = loc; #if IN_DMD this->sinit = NULL; #endif } Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) { Type *basetype = this->basetype->syntaxCopy(); Initializer *init = NULL; if (this->init) init = this->init->syntaxCopy(); assert(!s); TypedefDeclaration *st; st = new TypedefDeclaration(loc, ident, basetype, init); #ifdef _DH // Syntax copy for header file if (!htype) // Don't overwrite original { if (type) // Make copy for both old and new instances { htype = type->syntaxCopy(); st->htype = type->syntaxCopy(); } } else // Make copy of original for new instance st->htype = htype->syntaxCopy(); if (!hbasetype) { if (basetype) { hbasetype = basetype->syntaxCopy(); st->hbasetype = basetype->syntaxCopy(); } } else st->hbasetype = hbasetype->syntaxCopy(); #endif return st; } void TypedefDeclaration::semantic(Scope *sc) { //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); if (sem == 0) { sem = 1; basetype = basetype->semantic(loc, sc); sem = 2; #if DMDV2 type = type->addStorageClass(storage_class); #endif type = type->semantic(loc, sc); if (sc->parent->isFuncDeclaration() && init) semantic2(sc); storage_class |= sc->stc & STCdeprecated; } else if (sem == 1) { error("circular definition"); } } void TypedefDeclaration::semantic2(Scope *sc) { //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); if (sem == 2) { sem = 3; if (init) { init = init->semantic(sc, basetype); ExpInitializer *ie = init->isExpInitializer(); if (ie) { if (ie->exp->type == basetype) ie->exp->type = type; } } } } const char *TypedefDeclaration::kind() { return "typedef"; } Type *TypedefDeclaration::getType() { return type; } void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("typedef "); basetype->toCBuffer(buf, ident, hgs); if (init) { buf->writestring(" = "); init->toCBuffer(buf, hgs); } buf->writeByte(';'); buf->writenl(); } /********************************* AliasDeclaration ****************************/ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) : Declaration(id) { //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); //printf("type = '%s'\n", type->toChars()); this->loc = loc; this->type = type; this->aliassym = NULL; #ifdef _DH this->htype = NULL; this->haliassym = NULL; #endif this->overnext = NULL; this->inSemantic = 0; this->importprot = PROTundefined; assert(type); } AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) : Declaration(id) { //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); assert(s != this); this->loc = loc; this->type = NULL; this->aliassym = s; #ifdef _DH this->htype = NULL; this->haliassym = NULL; #endif this->overnext = NULL; this->inSemantic = 0; assert(s); } Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) { //printf("AliasDeclaration::syntaxCopy()\n"); assert(!s); AliasDeclaration *sa; if (type) sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); else sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); #ifdef _DH // Syntax copy for header file if (!htype) // Don't overwrite original { if (type) // Make copy for both old and new instances { htype = type->syntaxCopy(); sa->htype = type->syntaxCopy(); } } else // Make copy of original for new instance sa->htype = htype->syntaxCopy(); if (!haliassym) { if (aliassym) { haliassym = aliassym->syntaxCopy(s); sa->haliassym = aliassym->syntaxCopy(s); } } else sa->haliassym = haliassym->syntaxCopy(s); #endif return sa; } void AliasDeclaration::semantic(Scope *sc) { //printf("AliasDeclaration::semantic() %s\n", toChars()); if (aliassym) { if (aliassym->isTemplateInstance()) aliassym->semantic(sc); return; } this->inSemantic = 1; #if DMDV1 // don't really know why this is here if (storage_class & STCconst) error("cannot be const"); #endif storage_class |= sc->stc & STCdeprecated; // Given: // alias foo.bar.abc def; // it is not knowable from the syntax whether this is an alias // for a type or an alias for a symbol. It is up to the semantic() // pass to distinguish. // If it is a type, then type is set and getType() will return that // type. If it is a symbol, then aliassym is set and type is NULL - // toAlias() will return aliasssym. Dsymbol *s; Type *t; Expression *e; /* This section is needed because resolve() will: * const x = 3; * alias x y; * try to alias y to 3. */ s = type->toDsymbol(sc); if (s #if DMDV2 ` && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) #endif ) goto L2; // it's a symbolic alias #if DMDV2 type = type->addStorageClass(storage_class); if (storage_class & (STCref | STCnothrow | STCpure)) { // For 'ref' to be attached to function types, and picked // up by Type::resolve(), it has to go into sc. sc = sc->push(); sc->stc |= storage_class & (STCref | STCnothrow | STCpure | STCshared); type->resolve(loc, sc, &e, &t, &s); sc = sc->pop(); } else #endif type->resolve(loc, sc, &e, &t, &s); if (s) { goto L2; } else if (e) { // Try to convert Expression to Dsymbol if (e->op == TOKvar) { s = ((VarExp *)e)->var; goto L2; } else if (e->op == TOKfunction) { s = ((FuncExp *)e)->fd; goto L2; } else { error("cannot alias an expression %s", e->toChars()); t = e->type; } } else if (t) { type = t; } if (overnext) ScopeDsymbol::multiplyDefined(0, this, overnext); this->inSemantic = 0; return; L2: //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); type = NULL; VarDeclaration *v = s->isVarDeclaration(); if (v && v->linkage == LINKdefault) { error("forward reference of %s", v->toChars()); s = NULL; } else { FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); if (f) { if (overnext) { FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); fa->importprot = importprot; if (!fa->overloadInsert(overnext)) ScopeDsymbol::multiplyDefined(0, f, overnext); overnext = NULL; s = fa; s->parent = sc->parent; } } if (overnext) ScopeDsymbol::multiplyDefined(0, s, overnext); if (s == this) { assert(global.errors); s = NULL; } } if (!aliassym) aliassym = s; this->inSemantic = 0; } int AliasDeclaration::overloadInsert(Dsymbol *s) { /* Don't know yet what the aliased symbol is, so assume it can * be overloaded and check later for correctness. */ //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); if (overnext == NULL) { if (s == this) { return TRUE; } overnext = s; return TRUE; } else { return overnext->overloadInsert(s); } } const char *AliasDeclaration::kind() { return "alias"; } Type *AliasDeclaration::getType() { //printf("AliasDeclaration::getType() %s\n", type->toChars()); #if 0 if (!type->deco && scope) semantic(scope); if (type && !type->deco) error("forward reference to alias %s\n", toChars()); #endif return type; } Dsymbol *AliasDeclaration::toAlias() { //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); assert(this != aliassym); //static int count; if (++count == 75) exit(0); //*(char*)0=0; if (inSemantic) { error("recursive alias declaration"); aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); } Dsymbol *s = aliassym ? aliassym->toAlias() : this; return s; } void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("alias "); #if 0 && _DH if (hgs->hdrgen) { if (haliassym) { buf->writestring(haliassym->toChars()); buf->writeByte(' '); buf->writestring(ident->toChars()); } else htype->toCBuffer(buf, ident, hgs); } else #endif { if (aliassym) { buf->writestring(aliassym->toChars()); buf->writeByte(' '); buf->writestring(ident->toChars()); } else type->toCBuffer(buf, ident, hgs); } buf->writeByte(';'); buf->writenl(); } /********************************* VarDeclaration ****************************/ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) : Declaration(id) { //printf("VarDeclaration('%s')\n", id->toChars()); #ifdef DEBUG if (!type && !init) { printf("VarDeclaration('%s')\n", id->toChars()); //*(char*)0=0; } #endif assert(type || init); this->type = type; this->init = init; #ifdef _DH this->htype = NULL; this->hinit = NULL; #endif this->loc = loc; offset = 0; noscope = 0; #if DMDV1 nestedref = 0; #endif ctorinit = 0; aliassym = NULL; onstack = 0; canassign = 0; value = NULL; #if IN_LLVM aggrIndex = 0; // LDC anonDecl = NULL; offset2 = 0; nakedUse = false; availableExternally = true; // assume this unless proven otherwise #endif } Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) { //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); VarDeclaration *sv; if (s) { sv = (VarDeclaration *)s; } else { Initializer *init = NULL; if (this->init) { init = this->init->syntaxCopy(); //init->isExpInitializer()->exp->print(); //init->isExpInitializer()->exp->dump(0); } sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); sv->storage_class = storage_class; } #ifdef _DH // Syntax copy for header file if (!htype) // Don't overwrite original { if (type) // Make copy for both old and new instances { htype = type->syntaxCopy(); sv->htype = type->syntaxCopy(); } } else // Make copy of original for new instance sv->htype = htype->syntaxCopy(); if (!hinit) { if (init) { hinit = init->syntaxCopy(); sv->hinit = init->syntaxCopy(); } } else sv->hinit = hinit->syntaxCopy(); #endif return sv; } void VarDeclaration::semantic(Scope *sc) { #if 0 printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); printf(" type = %s\n", type ? type->toChars() : "null"); printf(" stc = x%x\n", sc->stc); printf(" storage_class = x%x\n", storage_class); printf("linkage = %d\n", sc->linkage); //if (strcmp(toChars(), "mul") == 0) halt(); #endif storage_class |= sc->stc; if (storage_class & STCextern && init) error("extern symbols cannot have initializers"); /* If auto type inference, do the inference */ int inferred = 0; if (!type) { inuse++; type = init->inferType(sc); inuse--; inferred = 1; /* This is a kludge to support the existing syntax for RAII * declarations. */ storage_class &= ~STCauto; originalType = type; } else { if (!originalType) originalType = type; type = type->semantic(loc, sc); } //printf(" semantic type = %s\n", type ? type->toChars() : "null"); type->checkDeprecated(loc, sc); linkage = sc->linkage; this->parent = sc->parent; //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); protection = sc->protection; //printf("sc->stc = %x\n", sc->stc); //printf("storage_class = x%x\n", storage_class); #if DMDV2 if (storage_class & STCgshared && global.params.safe && !sc->module->safe) { error("__gshared not allowed in safe mode; use shared"); } #endif Dsymbol *parent = toParent(); FuncDeclaration *fd = parent->isFuncDeclaration(); Type *tb = type->toBasetype(); if (tb->ty == Tvoid && !(storage_class & STClazy)) { error("voids have no value"); type = Type::terror; tb = type; } if (tb->ty == Tfunction) { error("cannot be declared to be a function"); type = Type::terror; tb = type; } if (tb->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tb; if (!ts->sym->members) { error("no definition of struct %s", ts->toChars()); } } if ((storage_class & STCauto) && !inferred) error("both auto and explicit type given"); if (tb->ty == Ttuple) { /* Instead, declare variables for each of the tuple elements * and add those. */ TypeTuple *tt = (TypeTuple *)tb; size_t nelems = Parameter::dim(tt->arguments); Objects *exps = new Objects(); exps->setDim(nelems); Expression *ie = init ? init->toExpression() : NULL; for (size_t i = 0; i < nelems; i++) { Parameter *arg = Parameter::getNth(tt->arguments, i); OutBuffer buf; buf.printf("_%s_field_%zu", ident->toChars(), i); buf.writeByte(0); char *name = (char *)buf.extractData(); Identifier *id = new Identifier(name, TOKidentifier); Expression *einit = ie; if (ie && ie->op == TOKtuple) { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; } Initializer *ti = init; if (einit) { ti = new ExpInitializer(einit->loc, einit); } VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); v->semantic(sc); #if !IN_LLVM // removed for LDC since TupleDeclaration::toObj already creates the fields; // adding them to the scope again leads to duplicates if (sc->scopesym) { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); if (sc->scopesym->members) sc->scopesym->members->push(v); } #endif Expression *e = new DsymbolExp(loc, v); exps->data[i] = e; } TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); v2->isexp = 1; aliassym = v2; return; } if (storage_class & STCconst && !init && !fd) // Initialize by constructor only storage_class = (storage_class & ~STCconst) | STCctorinit; if (isConst()) { } else if (isStatic()) { } else if (isSynchronized()) { error("variable %s cannot be synchronized", toChars()); } else if (isOverride()) { error("override cannot be applied to variable"); } else if (isAbstract()) { error("abstract cannot be applied to variable"); } else if (storage_class & STCtemplateparameter) { } else { AggregateDeclaration *aad = sc->anonAgg; if (!aad) aad = parent->isAggregateDeclaration(); if (aad) { #if DMDV2 assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); if (storage_class & (STCconst | STCimmutable) && init) { if (!type->toBasetype()->isTypeBasic()) storage_class |= STCstatic; } else #endif aad->addField(sc, this); } InterfaceDeclaration *id = parent->isInterfaceDeclaration(); if (id) { error("field not allowed in interface"); } /* Templates cannot add fields to aggregates */ TemplateInstance *ti = parent->isTemplateInstance(); if (ti) { // Take care of nested templates while (1) { TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); if (!ti2) break; ti = ti2; } // If it's a member template AggregateDeclaration *ad = ti->tempdecl->isMember(); if (ad && storage_class != STCundefined) { error("cannot use template to add field to aggregate '%s'", ad->toChars()); } } } #if DMDV2 if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && ident != Id::This) { error("only parameters or foreach declarations can be ref"); } #endif if (type->isscope() && !noscope) { if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) { error("globals, statics, fields, ref and out parameters cannot be scope"); } if (!(storage_class & STCscope)) { if (!(storage_class & STCparameter) && ident != Id::withSym) error("reference to scope class must be scope"); } } enum TOK op = TOKconstruct; if (!init && !sc->inunion && !isStatic() && !isConst() && fd && !(storage_class & (STCfield | STCin | STCforeach)) && type->size() != 0) { // Provide a default initializer //printf("Providing default initializer for '%s'\n", toChars()); if (type->ty == Tstruct && ((TypeStruct *)type)->sym->zeroInit == 1) { /* If a struct is all zeros, as a special case * set it's initializer to the integer 0. * In AssignExp::toElem(), we check for this and issue * a memset() to initialize the struct. * Must do same check in interpreter. */ Expression *e = new IntegerExp(loc, 0, Type::tint32); Expression *e1; e1 = new VarExp(loc, this); e = new AssignExp(loc, e1, e); e->op = TOKconstruct; e->type = e1->type; // don't type check this, it would fail init = new ExpInitializer(loc, e); return; } else if (type->ty == Ttypedef) { TypeTypedef *td = (TypeTypedef *)type; if (td->sym->init) { init = td->sym->init; ExpInitializer *ie = init->isExpInitializer(); if (ie) // Make copy so we can modify it init = new ExpInitializer(ie->loc, ie->exp); } else init = getExpInitializer(); } else { init = getExpInitializer(); } // Default initializer is always a blit op = TOKblit; } if (init) { sc = sc->push(); sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); ArrayInitializer *ai = init->isArrayInitializer(); if (ai && tb->ty == Taarray) { init = ai->toAssocArrayInitializer(); } StructInitializer *si = init->isStructInitializer(); ExpInitializer *ei = init->isExpInitializer(); // See if initializer is a NewExp that can be allocated on the stack if (ei && isScope() && ei->exp->op == TOKnew) { NewExp *ne = (NewExp *)ei->exp; if (!(ne->newargs && ne->newargs->dim)) { ne->onstack = 1; onstack = 1; if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) onstack = 2; } } // If inside function, there is no semantic3() call if (sc->func) { // If local variable, use AssignExp to handle all the various // possibilities. if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) { //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); if (!ei) { Expression *e = init->toExpression(); if (!e) { init = init->semantic(sc, type); e = init->toExpression(); if (!e) { error("is not a static and cannot have static initializer"); return; } } ei = new ExpInitializer(init->loc, e); init = ei; } Expression *e1 = new VarExp(loc, this); Type *t = type->toBasetype(); if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) { ei->exp = ei->exp->semantic(sc); if (!ei->exp->implicitConvTo(type)) { int dim = ((TypeSArray *)t)->dim->toInteger(); // If multidimensional static array, treat as one large array while (1) { t = t->nextOf()->toBasetype(); if (t->ty != Tsarray) break; dim *= ((TypeSArray *)t)->dim->toInteger(); e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); } } e1 = new SliceExp(loc, e1, NULL, NULL); } else if (t->ty == Tstruct) { ei->exp = ei->exp->semantic(sc); ei->exp = resolveProperties(sc, ei->exp); StructDeclaration *sd = ((TypeStruct *)t)->sym; #if DMDV2 /* Look to see if initializer is a call to the constructor */ if (sd->ctor && // there are constructors ei->exp->type->ty == Tstruct && // rvalue is the same struct ((TypeStruct *)ei->exp->type)->sym == sd && ei->exp->op == TOKstar) { /* Look for form of constructor call which is: * *__ctmp.ctor(arguments...) */ PtrExp *pe = (PtrExp *)ei->exp; if (pe->e1->op == TOKcall) { CallExp *ce = (CallExp *)pe->e1; if (ce->e1->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)ce->e1; if (dve->var->isCtorDeclaration()) { /* It's a constructor call, currently constructing * a temporary __ctmp. */ /* Before calling the constructor, initialize * variable with a bit copy of the default * initializer */ Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); e->op = TOKblit; e->type = t; ei->exp = new CommaExp(loc, e, ei->exp); /* Replace __ctmp being constructed with e1 */ dve->e1 = e1; return; } } } } #endif if (!ei->exp->implicitConvTo(type)) { /* Look for opCall * See bugzilla 2702 for more discussion */ Type *ti = ei->exp->type->toBasetype(); // Don't cast away invariant or mutability in initializer if (search_function(sd, Id::call) && /* Initializing with the same type is done differently */ !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) { // Rewrite as e1.call(arguments) Expression * eCall = new DotIdExp(loc, e1, Id::call); ei->exp = new CallExp(loc, eCall, ei->exp); } } } ei->exp = new AssignExp(loc, e1, ei->exp); ei->exp->op = TOKconstruct; canassign++; ei->exp = ei->exp->semantic(sc); canassign--; ei->exp->optimize(WANTvalue); } else { init = init->semantic(sc, type); if (fd && isConst() && !isStatic()) { // Make it static storage_class |= STCstatic; } } } else if (isConst() || isFinal() || parent->isAggregateDeclaration()) { /* Because we may need the results of a const declaration in a * subsequent type, such as an array dimension, before semantic2() * gets ordinarily run, try to run semantic2() now. * Ignore failure. */ if (!global.errors && !inferred) { unsigned errors = global.errors; global.gag++; //printf("+gag\n"); Expression *e; Initializer *i2 = init; inuse++; if (ei) { e = ei->exp->syntaxCopy(); e = e->semantic(sc); e = e->implicitCastTo(sc, type); } else if (si || ai) { i2 = init->syntaxCopy(); i2 = i2->semantic(sc, type); } inuse--; global.gag--; //printf("-gag\n"); if (errors != global.errors) // if errors happened { if (global.gag == 0) global.errors = errors; // act as if nothing happened #if DMDV2 /* Save scope for later use, to try again */ scope = new Scope(*sc); scope->setNoFree(); #endif } else if (ei) { e = e->optimize(WANTvalue | WANTinterpret); if (e->op == TOKint64 || e->op == TOKstring || e->op == TOKfloat64) { ei->exp = e; // no errors, keep result } #if DMDV2 else { /* Save scope for later use, to try again */ scope = new Scope(*sc); scope->setNoFree(); } #endif } else init = i2; // no errors, keep result } } sc = sc->pop(); } } ExpInitializer *VarDeclaration::getExpInitializer() { ExpInitializer *ei; if (init) ei = init->isExpInitializer(); else { Expression *e = type->defaultInit(loc); if (e) ei = new ExpInitializer(loc, e); else ei = NULL; } return ei; } void VarDeclaration::semantic2(Scope *sc) { //printf("VarDeclaration::semantic2('%s')\n", toChars()); if (init && !toParent()->isFuncDeclaration()) { inuse++; #if 0 ExpInitializer *ei = init->isExpInitializer(); if (ei) { ei->exp->dump(0); printf("type = %p\n", ei->exp->type); } #endif init = init->semantic(sc, type); inuse--; } } void VarDeclaration::semantic3(Scope *sc) { // LDC if (!global.params.useAvailableExternally) availableExternally = false; // Preserve call chain Declaration::semantic3(sc); } const char *VarDeclaration::kind() { return "variable"; } Dsymbol *VarDeclaration::toAlias() { //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); assert(this != aliassym); Dsymbol *s = aliassym ? aliassym->toAlias() : this; return s; } void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { StorageClassDeclaration::stcToCBuffer(buf, storage_class); /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() * too. */ if (type) type->toCBuffer(buf, ident, hgs); else buf->writestring(ident->toChars()); if (init) { buf->writestring(" = "); #if DMDV2 ExpInitializer *ie = init->isExpInitializer(); if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); else #endif init->toCBuffer(buf, hgs); } buf->writeByte(';'); buf->writenl(); } int VarDeclaration::needThis() { //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); return storage_class & STCfield; } int VarDeclaration::isImportedSymbol() { if (protection == PROTexport && !init && (isStatic() || isConst() || parent->isModule())) return TRUE; return FALSE; } void VarDeclaration::checkCtorConstInit() { if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) error("missing initializer in static constructor for const variable"); } /************************************ * Check to see if this variable is actually in an enclosing function * rather than the current one. */ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) { //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); if (parent && !isDataseg() && parent != sc->parent) { // The function that this variable is in FuncDeclaration *fdv = toParent()->isFuncDeclaration(); // The current function FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); if (fdv && fdthis) { if (loc.filename) fdthis->getLevel(loc, fdv); nestedref = 1; fdv->nestedFrameRef = 1; #if IN_LLVM #if DMDV1 fdv->nestedVars.insert(this); #endif #endif //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); } } } /******************************* * Does symbol go into data segment? * Includes extern variables. */ int VarDeclaration::isDataseg() { #if 0 printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); printf("%llx, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); printf("parent = '%s'\n", parent->toChars()); #endif Dsymbol *parent = this->toParent(); if (!parent && !(storage_class & (STCstatic | STCconst))) { error("forward referenced"); type = Type::terror; return 0; } return (storage_class & (STCstatic | STCconst) || parent->isModule() || parent->isTemplateInstance()); } /************************************ * Does symbol go into thread local storage? */ int VarDeclaration::isThreadlocal() { return 0; } /******************************************** * Can variable be read and written by CTFE? */ int VarDeclaration::isCTFE() { //printf("VarDeclaration::isCTFE(%p, '%s')\n", this, toChars()); //printf("%llx\n", storage_class); return (storage_class & STCctfe) || !isDataseg(); } int VarDeclaration::hasPointers() { //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); return (!isDataseg() && type->hasPointers()); } int VarDeclaration::isSameAsInitializer() { if (init && init->isExpInitializer() && init->isExpInitializer()->exp->op == TOKstructliteral) return 0; return isConst(); } /****************************************** * If a variable has an scope destructor call, return call for it. * Otherwise, return NULL. */ Expression *VarDeclaration::callScopeDtor(Scope *sc) { Expression *e = NULL; //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); if (storage_class & STCscope && !noscope) { for (ClassDeclaration *cd = type->isClassHandle(); cd; cd = cd->baseClass) { /* We can do better if there's a way with onstack * classes to determine if there's no way the monitor * could be set. */ //if (cd->isInterfaceDeclaration()) //error("interface %s cannot be scope", cd->toChars()); if (1 || onstack || cd->dtors.dim) // if any destructors { // delete this; Expression *ec; ec = new VarExp(loc, this); e = new DeleteExp(loc, ec); e->type = Type::tvoid; break; } } } return e; } /********************************* ClassInfoDeclaration ****************************/ ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) { this->cd = cd; storage_class = STCstatic; } Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) { assert(0); // should never be produced by syntax return NULL; } void ClassInfoDeclaration::semantic(Scope *sc) { } /********************************* ModuleInfoDeclaration ****************************/ ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) { this->mod = mod; storage_class = STCstatic; } Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) { assert(0); // should never be produced by syntax return NULL; } void ModuleInfoDeclaration::semantic(Scope *sc) { } /********************************* TypeInfoDeclaration ****************************/ TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) { this->tinfo = tinfo; storage_class = STCstatic; protection = PROTpublic; linkage = LINKc; } Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) { assert(0); // should never be produced by syntax return NULL; } void TypeInfoDeclaration::semantic(Scope *sc) { assert(linkage == LINKc); #if IN_LLVM if (!global.params.useAvailableExternally) availableExternally = false; #endif } /***************************** TypeInfoConstDeclaration **********************/ #if DMDV2 TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } #endif /***************************** TypeInfoInvariantDeclaration **********************/ #if DMDV2 TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } #endif /***************************** TypeInfoSharedDeclaration **********************/ #if DMDV2 TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } #endif /***************************** TypeInfoStructDeclaration **********************/ TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoClassDeclaration ***********************/ TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoInterfaceDeclaration *******************/ TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoTypedefDeclaration *********************/ TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoPointerDeclaration *********************/ TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoArrayDeclaration ***********************/ TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoStaticArrayDeclaration *****************/ TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoAssociativeArrayDeclaration ************/ TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoEnumDeclaration ***********************/ TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoFunctionDeclaration ********************/ TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoDelegateDeclaration ********************/ TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /***************************** TypeInfoTupleDeclaration **********************/ TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { } /********************************* ThisDeclaration ****************************/ // For the "this" parameter to member functions ThisDeclaration::ThisDeclaration(Loc loc, Type *t) : VarDeclaration(loc, t, Id::This, NULL) { noscope = 1; } Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) { assert(0); // should never be produced by syntax return NULL; } /********************** StaticStructInitDeclaration ***************************/ StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) : Declaration(new Identifier("", TOKidentifier)) { this->loc = loc; this->dsym = dsym; storage_class |= STCconst; }