Mercurial > projects > ldc
diff dmd2/attrib.c @ 1452:638d16625da2
LDC 2 compiles again.
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Sat, 30 May 2009 17:23:32 +0100 |
parents | 2667e3a145be |
children | 54b3c1394d62 |
line wrap: on
line diff
--- a/dmd2/attrib.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/attrib.c Sat May 30 17:23:32 2009 +0100 @@ -1,1483 +1,1553 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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 <stdlib.h> -#include <assert.h> - -#if _WIN32 || IN_GCC || IN_LLVM -#include "mem.h" -#elif POSIX -#include "../root/mem.h" -#endif - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "cond.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "module.h" -#include "parse.h" -#include "template.h" - -#include "../gen/enums.h" - - -#include "llvm/Support/CommandLine.h" - -static llvm::cl::opt<bool> ignoreUnsupportedPragmas("ignore", - llvm::cl::desc("Ignore unsupported pragmas"), - llvm::cl::ZeroOrMore); - - - -extern void obj_includelib(const char *name); -void obj_startaddress(Symbol *s); - - -/********************************* AttribDeclaration ****************************/ - -AttribDeclaration::AttribDeclaration(Array *decl) - : Dsymbol() -{ - this->decl = decl; -} - -Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - return decl; -} - -int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int m = 0; - Array *d = include(sc, sd); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - m |= s->addMember(sc, sd, m | memnum); - } - } - return m; -} - -void AttribDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, NULL); - - //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -void AttribDeclaration::semantic2(Scope *sc) -{ - Array *d = include(sc, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->semantic2(sc); - } - } -} - -void AttribDeclaration::semantic3(Scope *sc) -{ - Array *d = include(sc, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->semantic3(sc); - } - } -} - -void AttribDeclaration::inlineScan() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); - s->inlineScan(); - } - } -} - -void AttribDeclaration::addComment(unsigned char *comment) -{ - if (comment) - { - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - } -} - -void AttribDeclaration::emitComment(Scope *sc) -{ - //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); - - /* If generating doc comment, skip this because if we're inside - * a template, then include(NULL, NULL) will fail. - */ -// if (sc->docbuf) -// return; - - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::emitComment %s\n", s->toChars()); - s->emitComment(sc); - } - } -} - -void AttribDeclaration::toObjFile(int multiobj) -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->toObjFile(multiobj); - } - } -} - -int AttribDeclaration::cvMember(unsigned char *p) -{ - int nwritten = 0; - int n; - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - n = s->cvMember(p); - if (p) - p += n; - nwritten += n; - } - } - return nwritten; -} - -int AttribDeclaration::hasPointers() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - if (s->hasPointers()) - return 1; - } - } - return 0; -} - -const char *AttribDeclaration::kind() -{ - return "attribute"; -} - -int AttribDeclaration::oneMember(Dsymbol **ps) -{ - Array *d = include(NULL, NULL); - - return Dsymbol::oneMembers(d, ps); -} - -void AttribDeclaration::checkCtorConstInit() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->addLocalClass(aclasses); - } - } -} - - -void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (decl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - else - buf->writeByte(';'); - buf->writenl(); -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - StorageClassDeclaration *scd; - - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; -} - -void StorageClassDeclaration::semantic(Scope *sc) -{ - if (decl) - { unsigned stc_save = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest)) - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest); - if (stc & (STCconst | STCinvariant | STCmanifest)) - sc->stc &= ~(STCconst | STCinvariant | STCmanifest); - sc->stc |= stc; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->stc = stc_save; - } - else - sc->stc = stc; -} - -void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - struct SCstring - { - int stc; - enum TOK tok; - }; - - static SCstring table[] = - { - { STCauto, TOKauto }, - { STCscope, TOKscope }, - { STCstatic, TOKstatic }, - { STCextern, TOKextern }, - { STCconst, TOKconst }, - { STCinvariant, TOKimmutable }, - { STCshared, TOKshared }, - { STCfinal, TOKfinal }, - { STCabstract, TOKabstract }, - { STCsynchronized, TOKsynchronized }, - { STCdeprecated, TOKdeprecated }, - { STCoverride, TOKoverride }, - { STCnothrow, TOKnothrow }, - { STCpure, TOKpure }, - { STCref, TOKref }, - { STCtls, TOKtls }, - }; - - int written = 0; - for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) - { - if (stc & table[i].stc) - { - if (written) - buf->writeByte(' '); - written = 1; - buf->writestring(Token::toChars(table[i].tok)); - } - } - - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* LinkDeclaration ****************************/ - -LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) - : AttribDeclaration(decl) -{ - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = p; -} - -Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) -{ - LinkDeclaration *ld; - - assert(!s); - ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); - return ld; -} - -void LinkDeclaration::semantic(Scope *sc) -{ - //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::semantic3(Scope *sc) -{ - //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic3(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; - - switch (linkage) - { - case LINKd: p = "D"; break; - case LINKc: p = "C"; break; - case LINKcpp: p = "C++"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - default: - assert(0); - break; - } - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - -char *LinkDeclaration::toChars() -{ - return (char *)"extern ()"; -} - -/********************************* ProtDeclaration ****************************/ - -ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) - : AttribDeclaration(decl) -{ - protection = p; - //printf("decl = %p\n", decl); -} - -Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) -{ - ProtDeclaration *pd; - - assert(!s); - pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void ProtDeclaration::semantic(Scope *sc) -{ - if (decl) - { enum PROT protection_save = sc->protection; - int explicitProtection_save = sc->explicitProtection; - - sc->protection = protection; - sc->explicitProtection = 1; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->protection = protection_save; - sc->explicitProtection = explicitProtection_save; - } - else - { sc->protection = protection; - sc->explicitProtection = 1; - } -} - -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; - - switch (protection) - { - case PROTprivate: p = "private"; break; - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTpublic: p = "public"; break; - case PROTexport: p = "export"; break; - default: - assert(0); - break; - } - buf->writestring(p); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AlignDeclaration ****************************/ - -AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - salign = sa; -} - -Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) -{ - AlignDeclaration *ad; - - assert(!s); - ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AlignDeclaration::semantic(Scope *sc) -{ -// LDC -// we only support packed structs, as from the spec: align(1) struct Packed { ... } -// other alignments are simply ignored. my tests show this is what llvm-gcc does too ... - - //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); - if (decl) - { unsigned salign_save = sc->structalign; - - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - if (s->isStructDeclaration() && salign == 1) - { - sc->structalign = salign; - s->semantic(sc); - sc->structalign = salign_save; - } - else - { - s->semantic(sc); - } - } - sc->structalign = salign_save; - } - else - assert(0 && "what kind of align use triggers this?"); -} - - -void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->isunion = isunion; - this->scope = NULL; - this->sem = 0; -} - -Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) -{ - AnonDeclaration *ad; - - assert(!s); - ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AnonDeclaration::semantic(Scope *sc) -{ - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; - scope = NULL; - } - - assert(sc->parent); - - Dsymbol *parent = sc->parent->pastMixin(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - - if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) - { - error("can only be a part of an aggregate"); - return; - } - - if (decl) - { - AnonymousAggregateDeclaration aad; - int adisunion; - - if (sc->anonAgg) - { ad = sc->anonAgg; - adisunion = sc->inunion; - } - else - adisunion = ad->isUnionDeclaration() != NULL; - -// printf("\tsc->anonAgg = %p\n", sc->anonAgg); -// printf("\tad = %p\n", ad); -// printf("\taad = %p\n", &aad); - - sc = sc->push(); - sc->anonAgg = &aad; - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls); - sc->inunion = isunion; - sc->offset = 0; - sc->flags = 0; - aad.structalign = sc->structalign; - aad.parent = ad; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - if (isunion) - sc->offset = 0; - if (aad.sizeok == 2) - { - break; - } - } - sc = sc->pop(); - - // If failed due to forward references, unwind and try again later - if (aad.sizeok == 2) - { - ad->sizeok = 2; - //printf("\tsetting ad->sizeok %p to 2\n", ad); - if (!sc->anonAgg) - { - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - //printf("\tforward reference %p\n", this); - return; - } - if (sem == 0) - { Module::dprogress++; - sem = 1; - //printf("\tcompleted %p\n", this); - } - else - ;//printf("\talready completed %p\n", this); - - // 0 sized structs are set to 1 byte - if (aad.structsize == 0) - { - aad.structsize = 1; - aad.alignsize = 1; - } - - // Align size of anonymous aggregate -//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); - ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); - //ad->structsize = sc->offset; -//printf("sc->offset = %d\n", sc->offset); - - // Add members of aad to ad - //printf("\tadding members of aad (%p) to '%s'\n", &aad, ad->toChars()); - for (unsigned i = 0; i < aad.fields.dim; i++) - { - VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; - - // LDC - v->offset2 = sc->offset; - - v->offset += sc->offset; - - // LDC - if (!v->anonDecl) - v->anonDecl = this; - - ad->fields.push(v); - } - - // Add size of aad to ad - if (adisunion) - { - if (aad.structsize > ad->structsize) - ad->structsize = aad.structsize; - sc->offset = 0; - } - else - { - ad->structsize = sc->offset + aad.structsize; - sc->offset = ad->structsize; - } - - if (ad->alignsize < aad.alignsize) - ad->alignsize = aad.alignsize; - } -} - - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - //buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writestring("}\n"); -} - -const char *AnonDeclaration::kind() -{ - return (isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -static bool parseStringExp(Expression* e, std::string& res) -{ - StringExp *s = NULL; - - e = e->optimize(WANTvalue); - if (e->op == TOKstring && (s = (StringExp *)e)) - { - char* str = (char*)s->string; - res = str; - return true; - } - return false; -} - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - PragmaDeclaration *pd; - - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void PragmaDeclaration::semantic(Scope *sc) -{ // Should be merged with PragmaStatement - -#if IN_LLVM - int llvm_internal = 0; - std::string arg1str; - -#endif - - //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) - { - StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, se->string); - } - else - error("string expected for message, not '%s'", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - goto Lnodecl; - } - else if (ident == Id::lib) - { - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (Expression *)args->data[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } - goto Lnodecl; - } -#if IN_GCC - else if (ident == Id::GNU_asm) - { - if (! args || args->dim != 2) - error("identifier and string expected for asm name"); - else - { - Expression *e; - Declaration *d = NULL; - StringExp *s = NULL; - - e = (Expression *)args->data[0]; - e = e->semantic(sc); - if (e->op == TOKvar) - { - d = ((VarExp *)e)->var; - if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) - d = NULL; - } - if (!d) - error("first argument of GNU_asm must be a function or variable declaration"); - - e = (Expression *)args->data[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - if (e->op == TOKstring && ((StringExp *)e)->sz == 1) - s = ((StringExp *)e); - else - error("second argument of GNU_asm must be a char string"); - - if (d && s) - d->c_ident = Lexer::idPool((char*) s->string); - } - goto Lnodecl; - } -#endif - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (Expression *)args->data[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - } - goto Lnodecl; - } - - ///////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////// - // LDC -#if IN_LLVM - - // pragma(intrinsic, "string") { funcdecl(s) } - else if (ident == Id::intrinsic) - { - Expression* expr = (Expression *)args->data[0]; - expr = expr->semantic(sc); - if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) - { - error("requires exactly 1 string literal parameter"); - fatal(); - } - llvm_internal = LLVMintrinsic; - } - - // pragma(notypeinfo) { typedecl(s) } - else if (ident == Id::no_typeinfo) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMno_typeinfo; - } - - // pragma(nomoduleinfo) ; - else if (ident == Id::no_moduleinfo) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMno_moduleinfo; - } - - // pragma(alloca) { funcdecl(s) } - else if (ident == Id::Alloca) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMalloca; - } - - // pragma(va_start) { templdecl(s) } - else if (ident == Id::vastart) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_start; - } - - // pragma(va_copy) { funcdecl(s) } - else if (ident == Id::vacopy) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_copy; - } - - // pragma(va_end) { funcdecl(s) } - else if (ident == Id::vaend) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_end; - } - - // pragma(va_arg) { templdecl(s) } - else if (ident == Id::vaarg) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_arg; - } - - // pragma(ldc, "string") { templdecl(s) } - else if (ident == Id::ldc) - { - Expression* expr = (Expression *)args->data[0]; - expr = expr->semantic(sc); - if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) - { - error("requires exactly 1 string literal parameter"); - fatal(); - } - else if (arg1str == "verbose") - { - sc->module->llvmForceLogging = true; - } - else - { - error("command '%s' invalid"); - fatal(); - } - } - -#endif - // LDC - ///////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////// - - else if (ignoreUnsupportedPragmas) - { - if (global.params.verbose) - { - /* Print unrecognized pragmas - */ - printf("pragma %s", ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (i == 0) - printf(" ("); - else - printf(","); - printf("%s", e->toChars()); - } - if (args->dim) - printf(")"); - } - printf("\n"); - } - goto Lnodecl; - } - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - -// LDC -#if IN_LLVM - - if (llvm_internal) - { - if (s->llvmInternal) - { - error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); - fatal(); - } - switch(llvm_internal) - { - case LLVMintrinsic: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - fd->intrinsicName = arg1str; - fd->linkage = LINKintrinsic; - ((TypeFunction*)fd->type)->linkage = LINKintrinsic; - } - else if (TemplateDeclaration* td = s->isTemplateDeclaration()) - { - td->llvmInternal = llvm_internal; - td->intrinsicName = arg1str; - } - else - { - error("only allowed on function declarations"); - fatal(); - } - break; - - case LLVMva_start: - case LLVMva_arg: - if (TemplateDeclaration* td = s->isTemplateDeclaration()) - { - if (td->parameters->dim != 1) - { - error("the '%s' pragma template must have exactly one template parameter", ident->toChars()); - fatal(); - } - else if (!td->onemember) - { - error("the '%s' pragma template must have exactly one member", ident->toChars()); - fatal(); - } - else if (td->overnext || td->overroot) - { - error("the '%s' pragma template must not be overloaded", ident->toChars()); - fatal(); - } - td->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma is only allowed on template declarations", ident->toChars()); - fatal(); - } - break; - - case LLVMva_copy: - case LLVMva_end: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma is only allowed on function declarations", ident->toChars()); - fatal(); - } - break; - - case LLVMno_typeinfo: - s->llvmInternal = llvm_internal; - break; - - case LLVMalloca: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars()); - fatal(); - } - break; - - default: - warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); - } - } - -#endif // LDC - - } - } - return; - -Lnodecl: - if (decl) - error("pragma is missing closing ';'"); -} - -int PragmaDeclaration::oneMember(Dsymbol **ps) -{ - *ps = NULL; - return TRUE; -} - -const char *PragmaDeclaration::kind() -{ - return "pragma"; -} - -void PragmaDeclaration::toObjFile(int multiobj) -{ - if (ident == Id::lib) - { - assert(args && args->dim == 1); - - Expression *e = (Expression *)args->data[0]; - - assert(e->op == TOKstring); - - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - obj_includelib(name); - } - else if (ident == Id::startaddress) - { - assert(args && args->dim == 1); - Expression *e = (Expression *)args->data[0]; - Dsymbol *sa = getDsymbol(e); - FuncDeclaration *f = sa->isFuncDeclaration(); - assert(f); - Symbol *s = f->toSymbol(); - assert(0 && "startaddress pragma not implemented"); -// obj_startaddress(s); - } - AttribDeclaration::toObjFile(multiobj); -} - -void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("pragma (%s", ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - ConditionalDeclaration *dd; - - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int ConditionalDeclaration::oneMember(Dsymbol **ps) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Array *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps); - } - *ps = NULL; - return TRUE; -} - -void ConditionalDeclaration::emitComment(Scope *sc) -{ - //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); - if (condition->inc) - { - AttribDeclaration::emitComment(sc); - } -} - -// Decide if 'then' or 'else' code should be included - -Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("ConditionalDeclaration::include()\n"); - assert(condition); - return condition->include(sc, sd) ? decl : elsedecl; -} - - -void ConditionalDeclaration::addComment(unsigned char *comment) -{ - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - - if (comment) - { - Array *d = decl; - - for (int j = 0; j < 2; j++) - { - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - d = elsedecl; - } - } -} - -void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - if (decl || elsedecl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = (Dsymbol *)elsedecl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(':'); - buf->writenl(); -} - -/***************************** StaticIfDeclaration ****************************/ - -StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Array *decl, Array *elsedecl) - : ConditionalDeclaration(condition, decl, elsedecl) -{ - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - sd = NULL; - addisdone = 0; -} - - -Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticIfDeclaration *dd; - - assert(!s); - dd = new StaticIfDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); - /* This is deferred until semantic(), so that - * expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this->sd = sd; - int m = 0; - - if (memnum == 0) - { m = AttribDeclaration::addMember(sc, sd, memnum); - addisdone = 1; - } - return m; -} - - -void StaticIfDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, sd); - - //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - if (!addisdone) - { AttribDeclaration::addMember(sc, sd, 1); - addisdone = 1; - } - - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -const char *StaticIfDeclaration::kind() -{ - return "static if"; -} - - -/***************************** CompileDeclaration *****************************/ - -CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) - : AttribDeclaration(NULL) -{ - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); - this->loc = loc; - this->exp = exp; - this->sd = NULL; - this->compiled = 0; -} - -Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); - return sc; -} - -int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum); - this->sd = sd; - if (memnum == 0) - { /* No members yet, so parse the mixin now - */ - compileIt(sc); - memnum |= AttribDeclaration::addMember(sc, sd, memnum); - compiled = 1; - } - return memnum; -} - -void CompileDeclaration::compileIt(Scope *sc) -{ - //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) - { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); - } - else - { - StringExp *se = (StringExp *)exp; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - decl = p.parseDeclDefs(0); - if (p.token.value != TOKeof) - exp->error("incomplete mixin declaration (%s)", se->toChars()); - } -} - -void CompileDeclaration::semantic(Scope *sc) -{ - //printf("CompileDeclaration::semantic()\n"); - - if (!compiled) - { - compileIt(sc); - AttribDeclaration::addMember(sc, sd, 0); - compiled = 1; - } - AttribDeclaration::semantic(sc); -} - -void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - buf->writenl(); -} + +// 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 <stdlib.h> +#include <assert.h> + +#include "rmem.h" + +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "cond.h" +#include "scope.h" +#include "id.h" +#include "expression.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "module.h" +#include "parse.h" +#include "template.h" + +#if IN_LLVM +#include "../gen/enums.h" + +#include "llvm/Support/CommandLine.h" + +static llvm::cl::opt<bool> ignoreUnsupportedPragmas("ignore", + llvm::cl::desc("Ignore unsupported pragmas"), + llvm::cl::ZeroOrMore); + +#endif + + +extern void obj_includelib(const char *name); + +#if IN_DMD +void obj_startaddress(Symbol *s); +#endif + + +/********************************* AttribDeclaration ****************************/ + +AttribDeclaration::AttribDeclaration(Array *decl) + : Dsymbol() +{ + this->decl = decl; +} + +Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + return decl; +} + +int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + int m = 0; + Array *d = include(sc, sd); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + m |= s->addMember(sc, sd, m | memnum); + } + } + return m; +} + +void AttribDeclaration::semantic(Scope *sc) +{ + Array *d = include(sc, NULL); + + //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +void AttribDeclaration::semantic2(Scope *sc) +{ + Array *d = include(sc, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->semantic2(sc); + } + } +} + +void AttribDeclaration::semantic3(Scope *sc) +{ + Array *d = include(sc, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->semantic3(sc); + } + } +} + +void AttribDeclaration::inlineScan() +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); + s->inlineScan(); + } + } +} + +void AttribDeclaration::addComment(unsigned char *comment) +{ + if (comment) + { + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + } +} + +void AttribDeclaration::emitComment(Scope *sc) +{ + //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); + + /* A general problem with this, illustrated by BUGZILLA 2516, + * is that attributes are not transmitted through to the underlying + * member declarations for template bodies, because semantic analysis + * is not done for template declaration bodies + * (only template instantiations). + * Hence, Ddoc omits attributes from template members. + */ + + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::emitComment %s\n", s->toChars()); + s->emitComment(sc); + } + } +} + +#if IN_DMD + +void AttribDeclaration::toObjFile(int multiobj) +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->toObjFile(multiobj); + } + } +} + +int AttribDeclaration::cvMember(unsigned char *p) +{ + int nwritten = 0; + int n; + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + n = s->cvMember(p); + if (p) + p += n; + nwritten += n; + } + } + return nwritten; +} +#endif + +int AttribDeclaration::hasPointers() +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + if (s->hasPointers()) + return 1; + } + } + return 0; +} + +const char *AttribDeclaration::kind() +{ + return "attribute"; +} + +int AttribDeclaration::oneMember(Dsymbol **ps) +{ + Array *d = include(NULL, NULL); + + return Dsymbol::oneMembers(d, ps); +} + +void AttribDeclaration::checkCtorConstInit() +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->checkCtorConstInit(); + } + } +} + +/**************************************** + */ + +void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->addLocalClass(aclasses); + } + } +} + + +void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (decl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + else + buf->writeByte(';'); + buf->writenl(); +} + +/************************* StorageClassDeclaration ****************************/ + +StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl) + : AttribDeclaration(decl) +{ + this->stc = stc; +} + +Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) +{ + StorageClassDeclaration *scd; + + assert(!s); + scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); + return scd; +} + +void StorageClassDeclaration::semantic(Scope *sc) +{ + if (decl) + { unsigned stc_save = sc->stc; + + if (stc & (STCauto | STCscope | STCstatic | STCextern)) + sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern); + sc->stc |= stc; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->stc = stc_save; + } + else + sc->stc = stc; +} + +void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, int stc) +{ + struct SCstring + { + int stc; + enum TOK tok; + }; + + static SCstring table[] = + { + { STCauto, TOKauto }, + { STCscope, TOKscope }, + { STCstatic, TOKstatic }, + { STCextern, TOKextern }, + { STCconst, TOKconst }, + { STCimmutable, TOKimmutable }, + { STCshared, TOKshared }, + { STCfinal, TOKfinal }, + { STCabstract, TOKabstract }, + { STCsynchronized, TOKsynchronized }, + { STCdeprecated, TOKdeprecated }, + { STCoverride, TOKoverride }, + { STCnothrow, TOKnothrow }, + { STCpure, TOKpure }, + { STCref, TOKref }, + { STCtls, TOKtls }, + { STCgshared, TOKgshared }, + { STClazy, TOKlazy }, + { STCalias, TOKalias }, + { STCout, TOKout }, + { STCin, TOKin }, + }; + + for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) + { + if (stc & table[i].stc) + { + buf->writestring(Token::toChars(table[i].tok)); + buf->writeByte(' '); + } + } +} + +void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + stcToCBuffer(buf, stc); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* LinkDeclaration ****************************/ + +LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) + : AttribDeclaration(decl) +{ + //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); + linkage = p; +} + +Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) +{ + LinkDeclaration *ld; + + assert(!s); + ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); + return ld; +} + +void LinkDeclaration::semantic(Scope *sc) +{ + //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { enum LINK linkage_save = sc->linkage; + + sc->linkage = linkage; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->linkage = linkage_save; + } + else + { + sc->linkage = linkage; + } +} + +void LinkDeclaration::semantic3(Scope *sc) +{ + //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { enum LINK linkage_save = sc->linkage; + + sc->linkage = linkage; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic3(sc); + } + sc->linkage = linkage_save; + } + else + { + sc->linkage = linkage; + } +} + +void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ const char *p; + + switch (linkage) + { + case LINKd: p = "D"; break; + case LINKc: p = "C"; break; + case LINKcpp: p = "C++"; break; + case LINKwindows: p = "Windows"; break; + case LINKpascal: p = "Pascal"; break; + +#if IN_LLVM + case LINKintrinsic: p = "Intrinsic"; break; +#endif + default: + assert(0); + break; + } + buf->writestring("extern ("); + buf->writestring(p); + buf->writestring(") "); + AttribDeclaration::toCBuffer(buf, hgs); +} + +char *LinkDeclaration::toChars() +{ + return (char *)"extern ()"; +} + +/********************************* ProtDeclaration ****************************/ + +ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) + : AttribDeclaration(decl) +{ + protection = p; + //printf("decl = %p\n", decl); +} + +Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) +{ + ProtDeclaration *pd; + + assert(!s); + pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void ProtDeclaration::semantic(Scope *sc) +{ + if (decl) + { enum PROT protection_save = sc->protection; + int explicitProtection_save = sc->explicitProtection; + + sc->protection = protection; + sc->explicitProtection = 1; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->protection = protection_save; + sc->explicitProtection = explicitProtection_save; + } + else + { sc->protection = protection; + sc->explicitProtection = 1; + } +} + +void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ const char *p; + + switch (protection) + { + case PROTprivate: p = "private"; break; + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTpublic: p = "public"; break; + case PROTexport: p = "export"; break; + default: + assert(0); + break; + } + buf->writestring(p); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AlignDeclaration ****************************/ + +AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + salign = sa; +} + +Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) +{ + AlignDeclaration *ad; + + assert(!s); + ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AlignDeclaration::semantic(Scope *sc) +{ +// LDC +// we only support packed structs, as from the spec: align(1) struct Packed { ... } +// other alignments are simply ignored. my tests show this is what llvm-gcc does too ... + + //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); + if (decl) + { unsigned salign_save = sc->structalign; +#if IN_DMD + sc->structalign = salign; +#endif + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + if (s->isStructDeclaration() && salign == 1) + { + sc->structalign = salign; + s->semantic(sc); + sc->structalign = salign_save; + } + else + { + s->semantic(sc); + } + } + sc->structalign = salign_save; + } + else + assert(0 && "what kind of align use triggers this?"); +} + + +void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("align (%d)", salign); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AnonDeclaration ****************************/ + +AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->isunion = isunion; + this->scope = NULL; + this->sem = 0; +} + +Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) +{ + AnonDeclaration *ad; + + assert(!s); + ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AnonDeclaration::semantic(Scope *sc) +{ + //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; + scope = NULL; + } + + assert(sc->parent); + + Dsymbol *parent = sc->parent->pastMixin(); + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + + if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) + { + error("can only be a part of an aggregate"); + return; + } + + if (decl) + { + AnonymousAggregateDeclaration aad; + int adisunion; + + if (sc->anonAgg) + { ad = sc->anonAgg; + adisunion = sc->inunion; + } + else + adisunion = ad->isUnionDeclaration() != NULL; + +// printf("\tsc->anonAgg = %p\n", sc->anonAgg); +// printf("\tad = %p\n", ad); +// printf("\taad = %p\n", &aad); + + sc = sc->push(); + sc->anonAgg = &aad; + sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); + sc->inunion = isunion; + sc->offset = 0; + sc->flags = 0; + aad.structalign = sc->structalign; + aad.parent = ad; + + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + if (isunion) + sc->offset = 0; + if (aad.sizeok == 2) + { + break; + } + } + sc = sc->pop(); + + // If failed due to forward references, unwind and try again later + if (aad.sizeok == 2) + { + ad->sizeok = 2; + //printf("\tsetting ad->sizeok %p to 2\n", ad); + if (!sc->anonAgg) + { + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + //printf("\tforward reference %p\n", this); + return; + } + if (sem == 0) + { Module::dprogress++; + sem = 1; + //printf("\tcompleted %p\n", this); + } + else + ;//printf("\talready completed %p\n", this); + + // 0 sized structs are set to 1 byte + if (aad.structsize == 0) + { + aad.structsize = 1; + aad.alignsize = 1; + } + + // Align size of anonymous aggregate +//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); + ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); + //ad->structsize = sc->offset; +//printf("sc->offset = %d\n", sc->offset); + + // Add members of aad to ad + //printf("\tadding members of aad to '%s'\n", ad->toChars()); + for (unsigned i = 0; i < aad.fields.dim; i++) + { + VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; + +#if IN_LLVM + v->offset2 = sc->offset; +#endif + v->offset += sc->offset; + +#if IN_LLVM + if (!v->anonDecl) + v->anonDecl = this; +#endif + ad->fields.push(v); + } + + // Add size of aad to ad + if (adisunion) + { + if (aad.structsize > ad->structsize) + ad->structsize = aad.structsize; + sc->offset = 0; + } + else + { + ad->structsize = sc->offset + aad.structsize; + sc->offset = ad->structsize; + } + + if (ad->alignsize < aad.alignsize) + ad->alignsize = aad.alignsize; + } +} + + +void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf(isunion ? "union" : "struct"); + buf->writestring("\n{\n"); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + //buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writestring("}\n"); +} + +const char *AnonDeclaration::kind() +{ + return (isunion ? "anonymous union" : "anonymous struct"); +} + +/********************************* PragmaDeclaration ****************************/ + +static bool parseStringExp(Expression* e, std::string& res) +{ + StringExp *s = NULL; + + e = e->optimize(WANTvalue); + if (e->op == TOKstring && (s = (StringExp *)e)) + { + char* str = (char*)s->string; + res = str; + return true; + } + return false; +} + +PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->ident = ident; + this->args = args; +} + +Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); + PragmaDeclaration *pd; + + assert(!s); + pd = new PragmaDeclaration(loc, ident, + Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void PragmaDeclaration::semantic(Scope *sc) +{ // Should be merged with PragmaStatement + +#if IN_LLVM + int llvm_internal = 0; + std::string arg1str; +#endif + + //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); + if (ident == Id::msg) + { + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKstring) + { + StringExp *se = (StringExp *)e; + fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string); + } + else + error("string expected for message, not '%s'", e->toChars()); + } + fprintf(stdmsg, "\n"); + } + goto Lnodecl; + } + else if (ident == Id::lib) + { + if (!args || args->dim != 1) + error("string expected for library name"); + else + { + Expression *e = (Expression *)args->data[0]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + error("string expected for library name, not '%s'", e->toChars()); + else if (global.params.verbose) + { + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + printf("library %s\n", name); + mem.free(name); + } + } + goto Lnodecl; + } +#if IN_GCC + else if (ident == Id::GNU_asm) + { + if (! args || args->dim != 2) + error("identifier and string expected for asm name"); + else + { + Expression *e; + Declaration *d = NULL; + StringExp *s = NULL; + + e = (Expression *)args->data[0]; + e = e->semantic(sc); + if (e->op == TOKvar) + { + d = ((VarExp *)e)->var; + if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) + d = NULL; + } + if (!d) + error("first argument of GNU_asm must be a function or variable declaration"); + + e = (Expression *)args->data[1]; + e = e->semantic(sc); + e = e->optimize(WANTvalue); + if (e->op == TOKstring && ((StringExp *)e)->sz == 1) + s = ((StringExp *)e); + else + error("second argument of GNU_asm must be a char string"); + + if (d && s) + d->c_ident = Lexer::idPool((char*) s->string); + } + goto Lnodecl; + } +#endif + else if (ident == Id::startaddress) + { + if (!args || args->dim != 1) + error("function name expected for start address"); + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + Dsymbol *sa = getDsymbol(e); + if (!sa || !sa->isFuncDeclaration()) + error("function name expected for start address, not '%s'", e->toChars()); + } + goto Lnodecl; + } + +// LDC +#if IN_LLVM + + // pragma(intrinsic, "string") { funcdecl(s) } + else if (ident == Id::intrinsic) + { + Expression* expr = (Expression *)args->data[0]; + expr = expr->semantic(sc); + if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) + { + error("requires exactly 1 string literal parameter"); + fatal(); + } + llvm_internal = LLVMintrinsic; + } + + // pragma(notypeinfo) { typedecl(s) } + else if (ident == Id::no_typeinfo) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMno_typeinfo; + } + + // pragma(nomoduleinfo) ; + else if (ident == Id::no_moduleinfo) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMno_moduleinfo; + } + + // pragma(alloca) { funcdecl(s) } + else if (ident == Id::Alloca) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMalloca; + } + + // pragma(va_start) { templdecl(s) } + else if (ident == Id::vastart) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_start; + } + + // pragma(va_copy) { funcdecl(s) } + else if (ident == Id::vacopy) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_copy; + } + + // pragma(va_end) { funcdecl(s) } + else if (ident == Id::vaend) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_end; + } + + // pragma(va_arg) { templdecl(s) } + else if (ident == Id::vaarg) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_arg; + } + + // pragma(ldc, "string") { templdecl(s) } + else if (ident == Id::ldc) + { + Expression* expr = (Expression *)args->data[0]; + expr = expr->semantic(sc); + if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) + { + error("requires exactly 1 string literal parameter"); + fatal(); + } + else if (arg1str == "verbose") + { + sc->module->llvmForceLogging = true; + } + else + { + error("command '%s' invalid", expr->toChars()); + fatal(); + } + } + + // pragma(llvm_inline_asm) { templdecl(s) } + else if (ident == Id::llvm_inline_asm) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMinline_asm; + } + +#endif // LDC + + else if (ignoreUnsupportedPragmas) + { + if (global.params.verbose) + { + /* Print unrecognized pragmas + */ + printf("pragma %s", ident->toChars()); + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + // ignore errors in ignored pragmas. + global.gag++; + unsigned errors_save = global.errors; + + Expression *e = (Expression *)args->data[i]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (i == 0) + printf(" ("); + else + printf(","); + printf("%s", e->toChars()); + + // restore error state. + global.gag--; + global.errors = errors_save; + } + if (args->dim) + printf(")"); + } + printf("\n"); + } + } + else + error("unrecognized pragma(%s)", ident->toChars()); + + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + +// LDC +#if IN_LLVM + + if (llvm_internal) + { + if (s->llvmInternal) + { + error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); + fatal(); + } + switch(llvm_internal) + { + case LLVMintrinsic: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + fd->intrinsicName = arg1str; + fd->linkage = LINKintrinsic; + ((TypeFunction*)fd->type)->linkage = LINKintrinsic; + } + else if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + td->llvmInternal = llvm_internal; + td->intrinsicName = arg1str; + } + else + { + error("only allowed on function declarations"); + fatal(); + } + break; + + case LLVMva_start: + case LLVMva_arg: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + if (td->parameters->dim != 1) + { + error("the '%s' pragma template must have exactly one template parameter", ident->toChars()); + fatal(); + } + else if (!td->onemember) + { + error("the '%s' pragma template must have exactly one member", ident->toChars()); + fatal(); + } + else if (td->overnext || td->overroot) + { + error("the '%s' pragma template must not be overloaded", ident->toChars()); + fatal(); + } + td->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on template declarations", ident->toChars()); + fatal(); + } + break; + + case LLVMva_copy: + case LLVMva_end: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on function declarations", ident->toChars()); + fatal(); + } + break; + + case LLVMno_typeinfo: + s->llvmInternal = llvm_internal; + break; + + case LLVMalloca: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars()); + fatal(); + } + break; + + case LLVMinline_asm: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + if (td->parameters->dim > 1) + { + error("the '%s' pragma template must have exactly zero or one template parameters", ident->toChars()); + fatal(); + } + else if (!td->onemember) + { + error("the '%s' pragma template must have exactly one member", ident->toChars()); + fatal(); + } + td->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on template declarations", ident->toChars()); + fatal(); + } + break; + + default: + warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); + } + } + +#endif // LDC + + } + } + return; + +Lnodecl: + if (decl) + error("pragma is missing closing ';'"); +} + +int PragmaDeclaration::oneMember(Dsymbol **ps) +{ + *ps = NULL; + return TRUE; +} + +const char *PragmaDeclaration::kind() +{ + return "pragma"; +} + +#if IN_DMD +void PragmaDeclaration::toObjFile(int multiobj) +{ + if (ident == Id::lib) + { + assert(args && args->dim == 1); + + Expression *e = (Expression *)args->data[0]; + + assert(e->op == TOKstring); + + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; +#if OMFOBJ + /* The OMF format allows library names to be inserted + * into the object file. The linker will then automatically + * search that library, too. + */ + obj_includelib(name); +#elif ELFOBJ || MACHOBJ + /* The format does not allow embedded library names, + * so instead append the library name to the list to be passed + * to the linker. + */ + global.params.libfiles->push((void *) name); +#else + error("pragma lib not supported"); +#endif + } +#if DMDV2 + else if (ident == Id::startaddress) + { + assert(args && args->dim == 1); + Expression *e = (Expression *)args->data[0]; + Dsymbol *sa = getDsymbol(e); + FuncDeclaration *f = sa->isFuncDeclaration(); + assert(f); + Symbol *s = f->toSymbol(); + obj_startaddress(s); + } +#endif + AttribDeclaration::toObjFile(multiobj); +} +#endif + +void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("pragma (%s", ident->toChars()); + if (args && args->dim) + { + buf->writestring(", "); + argsToCBuffer(buf, args, hgs); + } + buf->writeByte(')'); + AttribDeclaration::toCBuffer(buf, hgs); +} + + +/********************************* ConditionalDeclaration ****************************/ + +ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) + : AttribDeclaration(decl) +{ + //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); + this->condition = condition; + this->elsedecl = elsedecl; +} + +Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) +{ + ConditionalDeclaration *dd; + + assert(!s); + dd = new ConditionalDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int ConditionalDeclaration::oneMember(Dsymbol **ps) +{ + //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); + if (condition->inc) + { + Array *d = condition->include(NULL, NULL) ? decl : elsedecl; + return Dsymbol::oneMembers(d, ps); + } + *ps = NULL; + return TRUE; +} + +void ConditionalDeclaration::emitComment(Scope *sc) +{ + //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); + if (condition->inc) + { + AttribDeclaration::emitComment(sc); + } + else if (sc->docbuf) + { + /* If generating doc comment, be careful because if we're inside + * a template, then include(NULL, NULL) will fail. + */ + Array *d = decl ? decl : elsedecl; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->emitComment(sc); + } + } +} + +// Decide if 'then' or 'else' code should be included + +Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("ConditionalDeclaration::include()\n"); + assert(condition); + return condition->include(sc, sd) ? decl : elsedecl; +} + + +void ConditionalDeclaration::addComment(unsigned char *comment) +{ + /* Because addComment is called by the parser, if we called + * include() it would define a version before it was used. + * But it's no problem to drill down to both decl and elsedecl, + * so that's the workaround. + */ + + if (comment) + { + Array *d = decl; + + for (int j = 0; j < 2; j++) + { + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + d = elsedecl; + } + } +} + +void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + condition->toCBuffer(buf, hgs); + if (decl || elsedecl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writeByte('}'); + if (elsedecl) + { + buf->writenl(); + buf->writestring("else"); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < elsedecl->dim; i++) + { + Dsymbol *s = (Dsymbol *)elsedecl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + } + else + buf->writeByte(':'); + buf->writenl(); +} + +/***************************** StaticIfDeclaration ****************************/ + +StaticIfDeclaration::StaticIfDeclaration(Condition *condition, + Array *decl, Array *elsedecl) + : ConditionalDeclaration(condition, decl, elsedecl) +{ + //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); + sd = NULL; + addisdone = 0; +} + + +Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticIfDeclaration *dd; + + assert(!s); + dd = new StaticIfDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); + /* This is deferred until semantic(), so that + * expressions in the condition can refer to declarations + * in the same scope, such as: + * + * template Foo(int i) + * { + * const int j = i + 1; + * static if (j == 3) + * const int k; + * } + */ + this->sd = sd; + int m = 0; + + if (memnum == 0) + { m = AttribDeclaration::addMember(sc, sd, memnum); + addisdone = 1; + } + return m; +} + + +void StaticIfDeclaration::semantic(Scope *sc) +{ + Array *d = include(sc, sd); + + //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); + if (d) + { + if (!addisdone) + { AttribDeclaration::addMember(sc, sd, 1); + addisdone = 1; + } + + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +const char *StaticIfDeclaration::kind() +{ + return "static if"; +} + + +/***************************** CompileDeclaration *****************************/ + +CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) + : AttribDeclaration(NULL) +{ + //printf("CompileDeclaration(loc = %d)\n", loc.linnum); + this->loc = loc; + this->exp = exp; + this->sd = NULL; + this->compiled = 0; +} + +Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); + CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); + return sc; +} + +int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum); + this->sd = sd; + if (memnum == 0) + { /* No members yet, so parse the mixin now + */ + compileIt(sc); + memnum |= AttribDeclaration::addMember(sc, sd, memnum); + compiled = 1; + } + return memnum; +} + +void CompileDeclaration::compileIt(Scope *sc) +{ + //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring) + { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); + } + else + { + StringExp *se = (StringExp *)exp; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + decl = p.parseDeclDefs(0); + if (p.token.value != TOKeof) + exp->error("incomplete mixin declaration (%s)", se->toChars()); + } +} + +void CompileDeclaration::semantic(Scope *sc) +{ + //printf("CompileDeclaration::semantic()\n"); + + if (!compiled) + { + compileIt(sc); + AttribDeclaration::addMember(sc, sd, 0); + compiled = 1; + } + AttribDeclaration::semantic(sc); +} + +void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + exp->toCBuffer(buf, hgs); + buf->writestring(");"); + buf->writenl(); +}