Logo Search packages:      
Sourcecode: ldc version File versions

attrib.c

// 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 },
//    { STCinvariant,    TOKimmutable },
//    { STCshared,       TOKshared },
      { STCfinal,        TOKfinal },
      { STCabstract,     TOKabstract },
      { STCsynchronized, TOKsynchronized },
      { STCdeprecated,   TOKdeprecated },
      { STCoverride,     TOKoverride },
//    { STCnothrow,      TOKnothrow },
//    { STCpure,         TOKpure },
//    { STCref,          TOKref },
//    { STCtls,          TOKtls },
    };

    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;

    // 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)
{
    //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

// 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;
      obj_includelib(name);
    }
#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)
    {
      for (size_t i = 0; i < args->dim; i++)
      {
          Expression *e = (Expression *)args->data[i];

          buf->writestring(", ");
          e->toCBuffer(buf, hgs);
      }
    }
    buf->writestring(")");
    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();
}

Generated by  Doxygen 1.6.0   Back to index