Logo Search packages:      
Sourcecode: ldc version File versions

statement.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 "statement.h"
#include "expression.h"
#include "cond.h"
#include "init.h"
#include "staticassert.h"
#include "mtype.h"
#include "scope.h"
#include "declaration.h"
#include "aggregate.h"
#include "id.h"
#include "hdrgen.h"
#include "parse.h"
#include "template.h"
#include "attrib.h"

/******************************** Statement ***************************/

Statement::Statement(Loc loc)
    : loc(loc)
{
#ifdef _DH
    // If this is an in{} contract scope statement (skip for determining
    //  inlineStatus of a function body for header content)
    incontract = 0;
#endif
}

Statement *Statement::syntaxCopy()
{
    assert(0);
    return NULL;
}

void Statement::print()
{
    fprintf(stdmsg, "%s\n", toChars());
    fflush(stdmsg);
}

char *Statement::toChars()
{   OutBuffer *buf;
    HdrGenState hgs;

    buf = new OutBuffer();
    toCBuffer(buf, &hgs);
    return buf->toChars();
}

void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->printf("Statement::toCBuffer()");
    buf->writenl();
}

Statement *Statement::semantic(Scope *sc)
{
    return this;
}

// Same as semantic(), but do create a new scope

Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue)
{   Scope *scd;
    Statement *s;

    scd = sc->push();
    if (sbreak)
      scd->sbreak = sbreak;
    if (scontinue)
      scd->scontinue = scontinue;
    s = semantic(scd);
    scd->pop();
    return s;
}

void Statement::error(const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    ::verror(loc, format, ap);
    va_end( ap );
}

void Statement::warning(const char *format, ...)
{
    if (global.params.warnings && !global.gag)
    {
      va_list ap;
      va_start(ap, format);
      ::vwarning(loc, format, ap);
      va_end( ap );
    }
}

int Statement::hasBreak()
{
    //printf("Statement::hasBreak()\n");
    return FALSE;
}

int Statement::hasContinue()
{
    return FALSE;
}

// TRUE if statement uses exception handling

int Statement::usesEH()
{
    return FALSE;
}

/* Only valid after semantic analysis
 */
int Statement::blockExit()
{
    printf("Statement::blockExit(%p)\n", this);
    printf("%s\n", toChars());
    assert(0);
    return BEany;
}

// TRUE if statement 'comes from' somewhere else, like a goto

int Statement::comeFrom()
{
    //printf("Statement::comeFrom()\n");
    return FALSE;
}

/****************************************
 * If this statement has code that needs to run in a finally clause
 * at the end of the current scope, return that code in the form of
 * a Statement.
 * Output:
 *    *sentry           code executed upon entry to the scope
 *    *sexception code executed upon exit from the scope via exception
 *    *sfinally   code executed in finally block
 */

void Statement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
{
    //printf("Statement::scopeCode()\n");
    //print();
    *sentry = NULL;
    *sexception = NULL;
    *sfinally = NULL;
}

/*********************************
 * Flatten out the scope by presenting the statement
 * as an array of statements.
 * Returns NULL if no flattening necessary.
 */

Statements *Statement::flatten(Scope *sc)
{
    return NULL;
}


/******************************** ExpStatement ***************************/

ExpStatement::ExpStatement(Loc loc, Expression *exp)
    : Statement(loc)
{
    this->exp = exp;
}

Statement *ExpStatement::syntaxCopy()
{
    Expression *e = exp ? exp->syntaxCopy() : NULL;
    ExpStatement *es = new ExpStatement(loc, e);
    return es;
}

void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    if (exp)
      exp->toCBuffer(buf, hgs);
    buf->writeByte(';');
    if (!hgs->FLinit.init)
        buf->writenl();
}

Statement *ExpStatement::semantic(Scope *sc)
{
    if (exp)
    {
      //printf("ExpStatement::semantic() %s\n", exp->toChars());
      exp = exp->semantic(sc);
      exp = resolveProperties(sc, exp);
      exp->checkSideEffect(0);
      exp = exp->optimize(0);
      if (exp->op == TOKdeclaration && !isDeclarationStatement())
      {   Statement *s = new DeclarationStatement(loc, exp);
          return s;
      }
      //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0);
    }
    return this;
}

int ExpStatement::blockExit()
{   int result = BEfallthru;

    if (exp)
    {
      if (exp->op == TOKhalt)
          return BEhalt;
      if (exp->op == TOKassert)
      {   AssertExp *a = (AssertExp *)exp;

          if (a->e1->isBool(FALSE)) // if it's an assert(0)
            return BEhalt;
      }
      if (exp->canThrow())
          result |= BEthrow;
    }
    return result;
}


/******************************** CompileStatement ***************************/

CompileStatement::CompileStatement(Loc loc, Expression *exp)
    : Statement(loc)
{
    this->exp = exp;
}

Statement *CompileStatement::syntaxCopy()
{
    Expression *e = exp->syntaxCopy();
    CompileStatement *es = new CompileStatement(loc, e);
    return es;
}

void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("mixin(");
    exp->toCBuffer(buf, hgs);
    buf->writestring(");");
    if (!hgs->FLinit.init)
        buf->writenl();
}

Statements *CompileStatement::flatten(Scope *sc)
{
    //printf("CompileStatement::flatten() %s\n", exp->toChars());
    exp = exp->semantic(sc);
    exp = resolveProperties(sc, exp);
    exp = exp->optimize(WANTvalue | WANTinterpret);
    if (exp->op != TOKstring)
    { error("argument to mixin must be a string, not (%s)", exp->toChars());
      return NULL;
    }
    StringExp *se = (StringExp *)exp;
    se = se->toUTF8(sc);
    Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
    p.loc = loc;
    p.nextToken();

    Statements *a = new Statements();
    while (p.token.value != TOKeof)
    {
      Statement *s = p.parseStatement(PSsemi | PScurlyscope);
      a->push(s);
    }
    return a;
}

Statement *CompileStatement::semantic(Scope *sc)
{
    //printf("CompileStatement::semantic() %s\n", exp->toChars());
    Statements *a = flatten(sc);
    if (!a)
      return NULL;
    Statement *s = new CompoundStatement(loc, a);
    return s->semantic(sc);
}


/******************************** DeclarationStatement ***************************/

DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration)
    : ExpStatement(loc, new DeclarationExp(loc, declaration))
{
}

DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp)
    : ExpStatement(loc, exp)
{
}

Statement *DeclarationStatement::syntaxCopy()
{
    DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy());
    return ds;
}

void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
{
    //printf("DeclarationStatement::scopeCode()\n");
    //print();

    *sentry = NULL;
    *sexception = NULL;
    *sfinally = NULL;

    if (exp)
    {
      if (exp->op == TOKdeclaration)
      {
          DeclarationExp *de = (DeclarationExp *)(exp);
          VarDeclaration *v = de->declaration->isVarDeclaration();
          if (v)
          { Expression *e;

            e = v->callScopeDtor();
            if (e)
            {
                //printf("dtor is: "); e->print();
                *sfinally = new ExpStatement(loc, e);
            }
          }
      }
    }
}

void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    exp->toCBuffer(buf, hgs);
}


/******************************** CompoundStatement ***************************/

CompoundStatement::CompoundStatement(Loc loc, Statements *s)
    : Statement(loc)
{
    statements = s;
}

CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
    : Statement(loc)
{
    statements = new Statements();
    statements->reserve(2);
    statements->push(s1);
    statements->push(s2);
}

Statement *CompoundStatement::syntaxCopy()
{
    Statements *a = new Statements();
    a->setDim(statements->dim);
    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *)statements->data[i];
      if (s)
          s = s->syntaxCopy();
      a->data[i] = s;
    }
    CompoundStatement *cs = new CompoundStatement(loc, a);
    return cs;
}


Statement *CompoundStatement::semantic(Scope *sc)
{   Statement *s;

    //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);

    for (size_t i = 0; i < statements->dim; )
    {
      s = (Statement *) statements->data[i];
      if (s)
      {   Statements *a = s->flatten(sc);

          if (a)
          {
            statements->remove(i);
            statements->insert(i, a);
            continue;
          }
          s = s->semantic(sc);
          statements->data[i] = s;
          if (s)
          {
            Statement *sentry;
            Statement *sexception;
            Statement *sfinally;

            s->scopeCode(&sentry, &sexception, &sfinally);
            if (sentry)
            {
                sentry = sentry->semantic(sc);
                statements->data[i] = sentry;
            }
            if (sexception)
            {
                if (i + 1 == statements->dim && !sfinally)
                {
#if 1
                  sexception = sexception->semantic(sc);
#else
                  statements->push(sexception);
                  if (sfinally)
                      // Assume sexception does not throw
                      statements->push(sfinally);
#endif
                }
                else
                {
                  /* Rewrite:
                   *    s; s1; s2;
                   * As:
                   *    s;
                   *    try { s1; s2; }
                   *    catch (Object __o)
                   *    { sexception; throw __o; }
                   */
                  Statement *body;
                  Statements *a = new Statements();

                  for (int j = i + 1; j < statements->dim; j++)
                  {
                      a->push(statements->data[j]);
                  }
                  body = new CompoundStatement(0, a);
                  body = new ScopeStatement(0, body);

                  Identifier *id = Lexer::uniqueId("__o");

                  Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
                  handler = new CompoundStatement(0, sexception, handler);

                  Array *catches = new Array();
                  Catch *ctch = new Catch(0, NULL, id, handler);
                  catches->push(ctch);
                  s = new TryCatchStatement(0, body, catches);

                  if (sfinally)
                      s = new TryFinallyStatement(0, s, sfinally);
                  s = s->semantic(sc);
                  statements->setDim(i + 1);
                  statements->push(s);
                  break;
                }
            }
            else if (sfinally)
            {
                if (0 && i + 1 == statements->dim)
                {
                  statements->push(sfinally);
                }
                else
                {
                  /* Rewrite:
                   *    s; s1; s2;
                   * As:
                   *    s; try { s1; s2; } finally { sfinally; }
                   */
                  Statement *body;
                  Statements *a = new Statements();

                  for (int j = i + 1; j < statements->dim; j++)
                  {
                      a->push(statements->data[j]);
                  }
                  body = new CompoundStatement(0, a);
                  s = new TryFinallyStatement(0, body, sfinally);
                  s = s->semantic(sc);
                  statements->setDim(i + 1);
                  statements->push(s);
                  break;
                }
            }
          }
      }
      i++;
    }
    if (statements->dim == 1 && !isAsmBlockStatement())
    {
      return (Statement *)statements->data[0];
    }
    return this;
}

Statements *CompoundStatement::flatten(Scope *sc)
{
    return statements;
}

ReturnStatement *CompoundStatement::isReturnStatement()
{
    ReturnStatement *rs = NULL;

    for (int i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *) statements->data[i];
      if (s)
      {
          rs = s->isReturnStatement();
          if (rs)
            break;
      }
    }
    return rs;
}

void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    for (int i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *) statements->data[i];
      if (s)
          s->toCBuffer(buf, hgs);
    }
}

int CompoundStatement::usesEH()
{
    for (int i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *) statements->data[i];
      if (s && s->usesEH())
          return TRUE;
    }
    return FALSE;
}

int CompoundStatement::blockExit()
{
    //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
    int result = BEfallthru;
    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *) statements->data[i];
      if (s)
      {
//printf("result = x%x\n", result);
//printf("%s\n", s->toChars());
          if (!(result & BEfallthru) && !s->comeFrom())
          {
            s->warning("statement is not reachable");
          }

          result &= ~BEfallthru;
          result |= s->blockExit();
      }
    }
    return result;
}

int CompoundStatement::comeFrom()
{   int comefrom = FALSE;

    //printf("CompoundStatement::comeFrom()\n");
    for (int i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *)statements->data[i];

      if (!s)
          continue;

      comefrom |= s->comeFrom();
    }
    return comefrom;
}


/******************************** CompoundDeclarationStatement ***************************/

CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s)
    : CompoundStatement(loc, s)
{
    statements = s;
}

Statement *CompoundDeclarationStatement::syntaxCopy()
{
    Statements *a = new Statements();
    a->setDim(statements->dim);
    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *)statements->data[i];
      if (s)
          s = s->syntaxCopy();
      a->data[i] = s;
    }
    CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a);
    return cs;
}

void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    int nwritten = 0;
    for (int i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *) statements->data[i];
      if (s)
      {   DeclarationStatement *ds = s->isDeclarationStatement();
          assert(ds);
          DeclarationExp *de = (DeclarationExp *)ds->exp;
          assert(de->op == TOKdeclaration);
          Declaration *d = de->declaration->isDeclaration();
          assert(d);
          VarDeclaration *v = d->isVarDeclaration();
          if (v)
          {
            /* This essentially copies the part of VarDeclaration::toCBuffer()
             * that does not print the type.
             * Should refactor this.
             */
            if (nwritten)
            {
                buf->writeByte(',');
                buf->writestring(v->ident->toChars());
            }
            else
            {
                StorageClassDeclaration::stcToCBuffer(buf, v->storage_class);
                if (v->type)
                  v->type->toCBuffer(buf, v->ident, hgs);
                else
                  buf->writestring(v->ident->toChars());
            }

            if (v->init)
            {   buf->writestring(" = ");
#if DMDV2
                ExpInitializer *ie = v->init->isExpInitializer();
                if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit))
                  ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs);
                else
#endif
                  v->init->toCBuffer(buf, hgs);
            }
          }
          else
            d->toCBuffer(buf, hgs);
          nwritten++;
      }
    }
    buf->writeByte(';');
    if (!hgs->FLinit.init)
        buf->writenl();
}

/**************************** UnrolledLoopStatement ***************************/

UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
    : Statement(loc)
{
    statements = s;
}

Statement *UnrolledLoopStatement::syntaxCopy()
{
    Statements *a = new Statements();
    a->setDim(statements->dim);
    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *)statements->data[i];
      if (s)
          s = s->syntaxCopy();
      a->data[i] = s;
    }
    UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
    return cs;
}


Statement *UnrolledLoopStatement::semantic(Scope *sc)
{
    //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);

    sc->noctor++;
    Scope *scd = sc->push();
    scd->sbreak = this;
    scd->scontinue = this;

    for (size_t i = 0; i < statements->dim; i++)
    {
      Statement *s = (Statement *) statements->data[i];
      if (s)
      {
          s = s->semantic(scd);
          statements->data[i] = s;
      }
    }

    scd->pop();
    sc->noctor--;
    return this;
}

void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("unrolled {");
    buf->writenl();

    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s;

      s = (Statement *) statements->data[i];
      if (s)
          s->toCBuffer(buf, hgs);
    }

    buf->writeByte('}');
    buf->writenl();
}

int UnrolledLoopStatement::hasBreak()
{
    return TRUE;
}

int UnrolledLoopStatement::hasContinue()
{
    return TRUE;
}

int UnrolledLoopStatement::usesEH()
{
    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *) statements->data[i];
      if (s && s->usesEH())
          return TRUE;
    }
    return FALSE;
}

int UnrolledLoopStatement::blockExit()
{
    int result = BEfallthru;
    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *) statements->data[i];
      if (s)
      {
          int r = s->blockExit();
          result |= r & ~(BEbreak | BEcontinue);
      }
    }
    return result;
}

int UnrolledLoopStatement::comeFrom()
{   int comefrom = FALSE;

    //printf("UnrolledLoopStatement::comeFrom()\n");
    for (size_t i = 0; i < statements->dim; i++)
    { Statement *s = (Statement *)statements->data[i];

      if (!s)
          continue;

      comefrom |= s->comeFrom();
    }
    return comefrom;
}


/******************************** ScopeStatement ***************************/

ScopeStatement::ScopeStatement(Loc loc, Statement *s)
    : Statement(loc)
{
    this->statement = s;
}

Statement *ScopeStatement::syntaxCopy()
{
    Statement *s;

    s = statement ? statement->syntaxCopy() : NULL;
    s = new ScopeStatement(loc, s);
    return s;
}


Statement *ScopeStatement::semantic(Scope *sc)
{   ScopeDsymbol *sym;

    //printf("ScopeStatement::semantic(sc = %p)\n", sc);
    if (statement)
    { Statements *a;

      sym = new ScopeDsymbol();
      sym->parent = sc->scopesym;
      sc = sc->push(sym);

      a = statement->flatten(sc);
      if (a)
      {
          statement = new CompoundStatement(loc, a);
      }

      statement = statement->semantic(sc);
      if (statement)
      {
          Statement *sentry;
          Statement *sexception;
          Statement *sfinally;

          statement->scopeCode(&sentry, &sexception, &sfinally);
          if (sfinally)
          {
            //printf("adding sfinally\n");
            statement = new CompoundStatement(loc, statement, sfinally);
          }
      }

      sc->pop();
    }
    return this;
}

int ScopeStatement::hasBreak()
{
    //printf("ScopeStatement::hasBreak() %s\n", toChars());
    return statement ? statement->hasBreak() : FALSE;
}

int ScopeStatement::hasContinue()
{
    return statement ? statement->hasContinue() : FALSE;
}

int ScopeStatement::usesEH()
{
    return statement ? statement->usesEH() : FALSE;
}

int ScopeStatement::blockExit()
{
    //printf("ScopeStatement::blockExit(%p)\n", statement);
    return statement ? statement->blockExit() : BEfallthru;
}

int ScopeStatement::comeFrom()
{
    //printf("ScopeStatement::comeFrom()\n");
    return statement ? statement->comeFrom() : FALSE;
}

void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writeByte('{');
    buf->writenl();

    if (statement)
      statement->toCBuffer(buf, hgs);

    buf->writeByte('}');
    buf->writenl();
}

/******************************** WhileStatement ***************************/

WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
    : Statement(loc)
{
    condition = c;
    body = b;
}

Statement *WhileStatement::syntaxCopy()
{
    WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
    return s;
}


Statement *WhileStatement::semantic(Scope *sc)
{
#if 0
    if (condition->op == TOKmatch)
    {
      /* Rewrite while (condition) body as:
       *   if (condition)
       *     do
       *       body
       *     while ((_match = _match.opNext), _match);
       */

      Expression *ew = new IdentifierExp(0, Id::_match);
      ew = new DotIdExp(0, ew, Id::next);
      ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
      ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
      Expression *ev = new IdentifierExp(0, Id::_match);
      //ev = new CastExp(0, ev, Type::tvoidptr);
      ew = new CommaExp(0, ew, ev);
      Statement *sw = new DoStatement(loc, body, ew);
      Statement *si = new IfStatement(loc, condition, sw, NULL);
      return si->semantic(sc);
    }
#endif

    condition = condition->semantic(sc);
    condition = resolveProperties(sc, condition);
    condition = condition->optimize(WANTvalue);
    condition = condition->checkToBoolean();

    sc->noctor++;

    Scope *scd = sc->push();
    scd->sbreak = this;
    scd->scontinue = this;
    if (body)
      body = body->semantic(scd);
    scd->pop();

    sc->noctor--;

    return this;
}

int WhileStatement::hasBreak()
{
    return TRUE;
}

int WhileStatement::hasContinue()
{
    return TRUE;
}

int WhileStatement::usesEH()
{
    return body ? body->usesEH() : 0;
}

int WhileStatement::blockExit()
{
    //printf("WhileStatement::blockExit(%p)\n", this);

    int result = BEnone;
    if (condition->canThrow())
      result |= BEthrow;
    if (condition->isBool(TRUE))
    {
      if (body)
      {   result |= body->blockExit();
          if (result & BEbreak)
            result |= BEfallthru;
      }
    }
    else if (condition->isBool(FALSE))
    {
      result |= BEfallthru;
    }
    else
    {
      if (body)
          result |= body->blockExit();
      result |= BEfallthru;
    }
    result &= ~(BEbreak | BEcontinue);
    return result;
}


int WhileStatement::comeFrom()
{
    if (body)
      return body->comeFrom();
    return FALSE;
}

void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("while (");
    condition->toCBuffer(buf, hgs);
    buf->writebyte(')');
    buf->writenl();
    if (body)
      body->toCBuffer(buf, hgs);
}

/******************************** DoStatement ***************************/

DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
    : Statement(loc)
{
    body = b;
    condition = c;
}

Statement *DoStatement::syntaxCopy()
{
    DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
    return s;
}


Statement *DoStatement::semantic(Scope *sc)
{
    sc->noctor++;
    if (body)
      body = body->semanticScope(sc, this, this);
    sc->noctor--;
    condition = condition->semantic(sc);
    condition = resolveProperties(sc, condition);
    condition = condition->optimize(WANTvalue);

    condition = condition->checkToBoolean();

    return this;
}

int DoStatement::hasBreak()
{
    return TRUE;
}

int DoStatement::hasContinue()
{
    return TRUE;
}

int DoStatement::usesEH()
{
    return body ? body->usesEH() : 0;
}

int DoStatement::blockExit()
{   int result;

    if (body)
    { result = body->blockExit();
      if (result == BEbreak)
          return BEfallthru;
      if (result & BEcontinue)
          result |= BEfallthru;
    }
    else
      result = BEfallthru;
    if (result & BEfallthru)
    { if (condition->canThrow())
          result |= BEthrow;
      if (!(result & BEbreak) && condition->isBool(TRUE))
          result &= ~BEfallthru;
    }
    result &= ~(BEbreak | BEcontinue);
    return result;
}


int DoStatement::comeFrom()
{
    if (body)
      return body->comeFrom();
    return FALSE;
}

void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("do");
    buf->writenl();
    if (body)
      body->toCBuffer(buf, hgs);
    buf->writestring("while (");
    condition->toCBuffer(buf, hgs);
    buf->writebyte(')');
}

/******************************** ForStatement ***************************/

ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
    : Statement(loc)
{
    this->init = init;
    this->condition = condition;
    this->increment = increment;
    this->body = body;
}

Statement *ForStatement::syntaxCopy()
{
    Statement *i = NULL;
    if (init)
      i = init->syntaxCopy();
    Expression *c = NULL;
    if (condition)
      c = condition->syntaxCopy();
    Expression *inc = NULL;
    if (increment)
      inc = increment->syntaxCopy();
    ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
    return s;
}

Statement *ForStatement::semantic(Scope *sc)
{
    ScopeDsymbol *sym = new ScopeDsymbol();
    sym->parent = sc->scopesym;
    sc = sc->push(sym);
    if (init)
      init = init->semantic(sc);
#if 0
    if (!condition)
      // Use a default value
      condition = new IntegerExp(loc, 1, Type::tboolean);
#endif
    sc->noctor++;
    if (condition)
    {
      condition = condition->semantic(sc);
      condition = resolveProperties(sc, condition);
      condition = condition->optimize(WANTvalue);
      condition = condition->checkToBoolean();
    }
    if (increment)
    { increment = increment->semantic(sc);
      increment = resolveProperties(sc, increment);
    }

    sc->sbreak = this;
    sc->scontinue = this;
    if (body)
      body = body->semantic(sc);
    sc->noctor--;

    sc->pop();
    return this;
}

void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
{
    //printf("ForStatement::scopeCode()\n");
    //print();
    if (init)
      init->scopeCode(sentry, sexception, sfinally);
    else
      Statement::scopeCode(sentry, sexception, sfinally);
}

int ForStatement::hasBreak()
{
    //printf("ForStatement::hasBreak()\n");
    return TRUE;
}

int ForStatement::hasContinue()
{
    return TRUE;
}

int ForStatement::usesEH()
{
    return (init && init->usesEH()) || body->usesEH();
}

int ForStatement::blockExit()
{   int result = BEfallthru;

    if (init)
    { result = init->blockExit();
      if (!(result & BEfallthru))
          return result;
    }
    if (condition)
    { if (condition->canThrow())
          result |= BEthrow;
    }
    else
      result &= ~BEfallthru;  // the body must do the exiting
    if (body)
    { int r = body->blockExit();
      if (r & (BEbreak | BEgoto))
          result |= BEfallthru;
      result |= r & ~(BEfallthru | BEbreak | BEcontinue);
    }
    if (increment && increment->canThrow())
      result |= BEthrow;
    return result;
}


int ForStatement::comeFrom()
{
    //printf("ForStatement::comeFrom()\n");
    if (body)
    { int result = body->comeFrom();
      //printf("result = %d\n", result);
      return result;
    }
    return FALSE;
}

void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("for (");
    if (init)
    {
        hgs->FLinit.init++;
        init->toCBuffer(buf, hgs);
        hgs->FLinit.init--;
    }
    else
        buf->writebyte(';');
    if (condition)
    {   buf->writebyte(' ');
        condition->toCBuffer(buf, hgs);
    }
    buf->writebyte(';');
    if (increment)
    {   buf->writebyte(' ');
        increment->toCBuffer(buf, hgs);
    }
    buf->writebyte(')');
    buf->writenl();
    buf->writebyte('{');
    buf->writenl();
    body->toCBuffer(buf, hgs);
    buf->writebyte('}');
    buf->writenl();
}

/******************************** ForeachStatement ***************************/

ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
      Expression *aggr, Statement *body)
    : Statement(loc)
{
    this->op = op;
    this->arguments = arguments;
    this->aggr = aggr;
    this->body = body;

    this->key = NULL;
    this->value = NULL;

    this->func = NULL;
}

Statement *ForeachStatement::syntaxCopy()
{
    Arguments *args = Argument::arraySyntaxCopy(arguments);
    Expression *exp = aggr->syntaxCopy();
    ForeachStatement *s = new ForeachStatement(loc, op, args, exp,
      body ? body->syntaxCopy() : NULL);
    return s;
}

Statement *ForeachStatement::semantic(Scope *sc)
{
    //printf("ForeachStatement::semantic() %p\n", this);
    ScopeDsymbol *sym;
    Statement *s = this;
    size_t dim = arguments->dim;
    TypeAArray *taa = NULL;

    Type *tn = NULL;
    Type *tnv = NULL;

    func = sc->func;
    if (func->fes)
      func = func->fes->func;

    aggr = aggr->semantic(sc);
    aggr = resolveProperties(sc, aggr);
    aggr = aggr->optimize(WANTvalue);
    if (!aggr->type)
    {
      error("invalid foreach aggregate %s", aggr->toChars());
      return this;
    }

    inferApplyArgTypes(op, arguments, aggr, sc->module);

    /* Check for inference errors
     */
    if (dim != arguments->dim)
    {
      //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
      error("cannot uniquely infer foreach argument types");
      return this;
    }

    Type *tab = aggr->type->toBasetype();

    if (tab->ty == Ttuple)    // don't generate new scope for tuple loops
    {
      if (dim < 1 || dim > 2)
      {
          error("only one (value) or two (key,value) arguments for tuple foreach");
          return s;
      }

      TypeTuple *tuple = (TypeTuple *)tab;
      Statements *statements = new Statements();
      //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
      size_t n;
      TupleExp *te = NULL;
      if (aggr->op == TOKtuple)     // expression tuple
      {   te = (TupleExp *)aggr;
          n = te->exps->dim;
      }
      else if (aggr->op == TOKtype) // type tuple
      {
          n = Argument::dim(tuple->arguments);
      }
      else
          assert(0);
      for (size_t j = 0; j < n; j++)
      {   size_t k = (op == TOKforeach) ? j : n - 1 - j;
          Expression *e;
          Type *t;
          if (te)
            e = (Expression *)te->exps->data[k];
          else
            t = Argument::getNth(tuple->arguments, k)->type;
          Argument *arg = (Argument *)arguments->data[0];
          Statements *st = new Statements();

          if (dim == 2)
          {   // Declare key
            if (arg->storageClass & (STCout | STCref | STClazy))
                error("no storage class for key %s", arg->ident->toChars());
            TY keyty = arg->type->ty;
            if (keyty != Tint32 && keyty != Tuns32)
            {
                if (global.params.is64bit)
                {
                  if (keyty != Tint64 && keyty != Tuns64)
                      error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars());
                }
                else
                  error("foreach: key type must be int or uint, not %s", arg->type->toChars());
            }
            Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
            VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
            var->storage_class |= STCconst;
            DeclarationExp *de = new DeclarationExp(loc, var);
            st->push(new ExpStatement(loc, de));
            arg = (Argument *)arguments->data[1];     // value
          }
          // Declare value
          if (arg->storageClass & (STCout | STCref | STClazy))
            error("no storage class for value %s", arg->ident->toChars());
          Dsymbol *var;
          if (te)
          {
            if (e->type->toBasetype()->ty == Tfunction &&
                e->op == TOKvar)
            {   VarExp *ve = (VarExp *)e;
                var = new AliasDeclaration(loc, arg->ident, ve->var);
            }
            else
            {
                arg->type = e->type;
                Initializer *ie = new ExpInitializer(0, e);
                VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
                if (e->isConst())
                  v->storage_class |= STCconst;
                var = v;
            }
          }
          else
          {
            var = new AliasDeclaration(loc, arg->ident, t);
          }
          DeclarationExp *de = new DeclarationExp(loc, var);
          st->push(new ExpStatement(loc, de));

          st->push(body->syntaxCopy());
          s = new CompoundStatement(loc, st);
          s = new ScopeStatement(loc, s);
          statements->push(s);
      }

      s = new UnrolledLoopStatement(loc, statements);
      s = s->semantic(sc);
      return s;
    }

    for (size_t i = 0; i < dim; i++)
    { Argument *arg = (Argument *)arguments->data[i];
      if (!arg->type)
      {
          error("cannot infer type for %s", arg->ident->toChars());
          return this;
      }
    }

    sym = new ScopeDsymbol();
    sym->parent = sc->scopesym;
    sc = sc->push(sym);

    sc->noctor++;

    switch (tab->ty)
    {
      case Tarray:
      case Tsarray:
          if (dim < 1 || dim > 2)
          {
            error("only one or two arguments for array foreach");
            break;
          }

          /* Look for special case of parsing char types out of char type
           * array.
           */
          tn = tab->nextOf()->toBasetype();
          if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
          { Argument *arg;

            int i = (dim == 1) ? 0 : 1;   // index of value
            arg = (Argument *)arguments->data[i];
            arg->type = arg->type->semantic(loc, sc);
            tnv = arg->type->toBasetype();
            if (tnv->ty != tn->ty &&
                (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
            {
                if (arg->storageClass & STCref)
                  error("foreach: value of UTF conversion cannot be ref");
                if (dim == 2)
                { arg = (Argument *)arguments->data[0];
                  if (arg->storageClass & STCref)
                      error("foreach: key cannot be ref");
                }
                goto Lapply;
            }
          }

          for (size_t i = 0; i < dim; i++)
          { // Declare args
            Argument *arg = (Argument *)arguments->data[i];
            VarDeclaration *var;

            var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
            var->storage_class |= STCforeach;
            var->storage_class |= arg->storageClass & (STCin | STCout | STCref);
#if 1
            DeclarationExp *de = new DeclarationExp(loc, var);
            de->semantic(sc);
#else
            var->semantic(sc);
            if (!sc->insert(var))
                error("%s already defined", var->ident->toChars());
#endif
            if (dim == 2 && i == 0)
                key = var;
            else
                value = var;
          }

          sc->sbreak = this;
          sc->scontinue = this;
          body = body->semantic(sc);

          if (!value->type->equals(tab->next))
          {
            if (aggr->op == TOKstring)
                aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
            else
                error("foreach: %s is not an array of %s",
                  tab->toChars(), value->type->toChars());
          }

          if (key && key->type->ty != Tint32 && key->type->ty != Tuns32)
          {
            if (global.params.is64bit)
            {
                if (key->type->ty != Tint64 && key->type->ty != Tuns64)
                  error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars());
            }
            else
                error("foreach: key type must be int or uint, not %s", key->type->toChars());
          }

          if (key && key->storage_class & (STCout | STCref))
            error("foreach: key cannot be out or ref");
          break;

      case Taarray:
          taa = (TypeAArray *)tab;
          if (dim < 1 || dim > 2)
          {
            error("only one or two arguments for associative array foreach");
            break;
          }
          if (op == TOKforeach_reverse)
          {
            error("no reverse iteration on associative arrays");
          }
          goto Lapply;

      case Tclass:
      case Tstruct:
#if DMDV2
      {   /* Look for range iteration, i.e. the properties
           * .empty, .next, .retreat, .head and .rear
           *    foreach (e; range) { ... }
           * translates to:
           *    for (auto __r = range; !__r.empty; __r.next)
           *    {   auto e = __r.head;
           *        ...
           *    }
           */
          if (dim != 1) // only one argument allowed with ranges
            goto Lapply;
          AggregateDeclaration *ad = (tab->ty == Tclass)
                  ? (AggregateDeclaration *)((TypeClass  *)tab)->sym
                  : (AggregateDeclaration *)((TypeStruct *)tab)->sym;
          Identifier *idhead;
          Identifier *idnext;
          if (op == TOKforeach)
          { idhead = Id::Fhead;
            idnext = Id::Fnext;
          }
          else
          { idhead = Id::Frear;
            idnext = Id::Fretreat;
          }
          Dsymbol *shead = search_function(ad, idhead);
          if (!shead)
            goto Lapply;

          /* Generate a temporary __r and initialize it with the aggregate.
           */
          Identifier *id = Identifier::generateId("__r");
          VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, aggr));
          r->semantic(sc);
          Statement *init = new DeclarationStatement(loc, r);

          // !__r.empty
          Expression *e = new VarExp(loc, r);
          e = new DotIdExp(loc, e, Id::Fempty);
          Expression *condition = new NotExp(loc, e);

          // __r.next
          e = new VarExp(loc, r);
          Expression *increment = new DotIdExp(loc, e, idnext);

          /* Declaration statement for e:
           *    auto e = __r.idhead;
           */
          e = new VarExp(loc, r);
          Expression *einit = new DotIdExp(loc, e, idhead);
          einit = einit->semantic(sc);
          Argument *arg = (Argument *)arguments->data[0];
          VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit));
          ve->storage_class |= STCforeach;
          ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant);

          DeclarationExp *de = new DeclarationExp(loc, ve);

          Statement *body = new CompoundStatement(loc,
            new DeclarationStatement(loc, de), this->body);

          s = new ForStatement(loc, init, condition, increment, body);
          s = s->semantic(sc);
          break;
      }
#endif
      case Tdelegate:
      Lapply:
      {   FuncDeclaration *fdapply;
          Arguments *args;
          Expression *ec;
          Expression *e;
          FuncLiteralDeclaration *fld;
          Argument *a;
          Type *t;
          Expression *flde;
          Identifier *id;
          Type *tret;
        TypeDelegate* dgty;
        TypeDelegate* dgty2;
        TypeDelegate* fldeTy;

          tret = func->type->nextOf();

          // Need a variable to hold value from any return statements in body.
          if (!sc->func->vresult && tret && tret != Type::tvoid)
          { VarDeclaration *v;

            v = new VarDeclaration(loc, tret, Id::result, NULL);
            v->noscope = 1;
            v->semantic(sc);
            if (!sc->insert(v))
                assert(0);
            v->parent = sc->func;
            sc->func->vresult = v;
          }

          /* Turn body into the function literal:
           *      int delegate(ref T arg) { body }
           */
          args = new Arguments();
          for (size_t i = 0; i < dim; i++)
          { Argument *arg = (Argument *)arguments->data[i];

            arg->type = arg->type->semantic(loc, sc);
            if (arg->storageClass & STCref)
                id = arg->ident;
            else
            {   // Make a copy of the ref argument so it isn't
                // a reference.
                VarDeclaration *v;
                Initializer *ie;

                id = Lexer::uniqueId("__applyArg", i);

                ie = new ExpInitializer(0, new IdentifierExp(0, id));
                v = new VarDeclaration(0, arg->type, arg->ident, ie);
                s = new DeclarationStatement(0, v);
                body = new CompoundStatement(loc, s, body);
            }
            a = new Argument(STCref, arg->type, id, NULL);
            args->push(a);
          }
          t = new TypeFunction(args, Type::tint32, 0, LINKd);
          fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
          fld->fbody = body;
          flde = new FuncExp(loc, fld);
          flde = flde->semantic(sc);

          // Resolve any forward referenced goto's
          for (int i = 0; i < gotos.dim; i++)
          { CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
            GotoStatement *gs = (GotoStatement *)cs->statements->data[0];

            if (!gs->label->statement)
            {   // 'Promote' it to this scope, and replace with a return
                cases.push(gs);
                s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
                cs->statements->data[0] = (void *)s;
            }
          }

          if (tab->ty == Taarray)
          {
            // Check types
            Argument *arg = (Argument *)arguments->data[0];
            if (dim == 2)
            {
                if (arg->storageClass & STCref)
                  error("foreach: index cannot be ref");
                if (!arg->type->equals(taa->index))
                  error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
                arg = (Argument *)arguments->data[1];
            }
            if (!arg->type->equals(taa->nextOf()))
                error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());

            /* Call:
             *    _aaApply(aggr, keysize, flde)
             */
            //LDC: Build arguments.
            static FuncDeclaration *aaApply2_fd = NULL;
        static TypeDelegate* aaApply2_dg;
            if(!aaApply2_fd) {
                Arguments* args = new Arguments;
                args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
                args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
                Arguments* dgargs = new Arguments;
                dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
                dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
                aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
                args->push(new Argument(STCin, aaApply2_dg, NULL, NULL));
                aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2");
            }
            static FuncDeclaration *aaApply_fd = NULL;
        static TypeDelegate* aaApply_dg;
            if(!aaApply_fd) {
                Arguments* args = new Arguments;
                args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
                args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
                Arguments* dgargs = new Arguments;
                dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
                aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
                args->push(new Argument(STCin, aaApply_dg, NULL, NULL));
                aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply");
            }
            if (dim == 2) {
                fdapply = aaApply2_fd;
            fldeTy = aaApply2_dg;
            } else {
                fdapply = aaApply_fd;
            fldeTy = aaApply_dg;
            }
            ec = new VarExp(0, fdapply);
            Expressions *exps = new Expressions();
            exps->push(aggr);
            size_t keysize = taa->key->size();
            keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1);
            exps->push(new IntegerExp(0, keysize, Type::tsize_t));

        // LDC paint delegate argument to the type runtime expects
        if (!fldeTy->equals(flde->type))
        {
            flde = new CastExp(loc, flde, flde->type);
            flde->type = fldeTy;
        }
            exps->push(flde);
            e = new CallExp(loc, ec, exps);
            e->type = Type::tindex; // don't run semantic() on e
          }
          else if (tab->ty == Tarray || tab->ty == Tsarray)
          {
            /* Call:
             *    _aApply(aggr, flde)
             */
            static char fntab[9][3] =
            { "cc","cw","cd",
              "wc","cc","wd",
              "dc","dw","dd"
            };
            char fdname[7+1+2+ sizeof(dim)*3 + 1];
            int flag;

            switch (tn->ty)
            {
                case Tchar:         flag = 0; break;
                case Twchar:  flag = 3; break;
                case Tdchar:  flag = 6; break;
                default:            assert(0);
            }
            switch (tnv->ty)
            {
                case Tchar:         flag += 0; break;
                case Twchar:  flag += 1; break;
                case Tdchar:  flag += 2; break;
                default:            assert(0);
            }
            const char *r = (op == TOKforeach_reverse) ? "R" : "";
#ifdef __MINGW32__
            int j = sprintf(fdname, "_aApply%s%.*s%lu", r, 2, fntab[flag], dim);
#else
            int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim);
#endif
            assert(j < sizeof(fdname));
            //LDC: Build arguments.
            Arguments* args = new Arguments;
            args->push(new Argument(STCin, tn->arrayOf(), NULL, NULL));
            if (dim == 2) {
                Arguments* dgargs = new Arguments;
                dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
                dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
                dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
                args->push(new Argument(STCin, dgty, NULL, NULL));
                fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname);
            } else {
                Arguments* dgargs = new Arguments;
                dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
                dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
                args->push(new Argument(STCin, dgty, NULL, NULL));
                fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname);
            }

            ec = new VarExp(0, fdapply);
            Expressions *exps = new Expressions();
            if (tab->ty == Tsarray)
               aggr = aggr->castTo(sc, tn->arrayOf());
        exps->push(aggr);

        // LDC paint delegate argument to the type runtime expects
        if (!dgty->equals(flde->type))
        {
            flde = new CastExp(loc, flde, flde->type);
            flde->type = dgty;
        }
            exps->push(flde);
            e = new CallExp(loc, ec, exps);
            e->type = Type::tindex; // don't run semantic() on e
          }
          else if (tab->ty == Tdelegate)
          {
            /* Call:
             *    aggr(flde)
             */
            Expressions *exps = new Expressions();
            exps->push(flde);
            e = new CallExp(loc, aggr, exps);
            e = e->semantic(sc);
            if (e->type != Type::tint32)
                error("opApply() function for %s must return an int", tab->toChars());
          }
          else
          {
            /* Call:
             *    aggr.apply(flde)
             */
            ec = new DotIdExp(loc, aggr,
                  (op == TOKforeach_reverse) ? Id::applyReverse
                                       : Id::apply);
            Expressions *exps = new Expressions();
            exps->push(flde);
            e = new CallExp(loc, ec, exps);
            e = e->semantic(sc);
            if (e->type != Type::tint32)
                error("opApply() function for %s must return an int", tab->toChars());
          }

          if (!cases.dim)
            // Easy case, a clean exit from the loop
            s = new ExpStatement(loc, e);
          else
          { // Construct a switch statement around the return value
            // of the apply function.
            Statements *a = new Statements();

            // default: break; takes care of cases 0 and 1
            s = new BreakStatement(0, NULL);
            s = new DefaultStatement(0, s);
            a->push(s);

            // cases 2...
            for (int i = 0; i < cases.dim; i++)
            {
                s = (Statement *)cases.data[i];
                s = new CaseStatement(0, new IntegerExp(i + 2), s);
                a->push(s);
            }

            s = new CompoundStatement(loc, a);
            s = new SwitchStatement(loc, e, s);
            s = s->semantic(sc);
          }
          break;
      }

      default:
          error("foreach: %s is not an aggregate type", aggr->type->toChars());
          break;
    }
    sc->noctor--;
    sc->pop();
    return s;
}

int ForeachStatement::hasBreak()
{
    return TRUE;
}

int ForeachStatement::hasContinue()
{
    return TRUE;
}

int ForeachStatement::usesEH()
{
    return body->usesEH();
}

int ForeachStatement::blockExit()
{   int result = BEfallthru;

    if (aggr->canThrow())
      result |= BEthrow;

    if (body)
    {
      result |= body->blockExit() & ~(BEbreak | BEcontinue);
    }
    return result;
}

int ForeachStatement::comeFrom()
{
    if (body)
      return body->comeFrom();
    return FALSE;
}

void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring(Token::toChars(op));
    buf->writestring(" (");
    for (int i = 0; i < arguments->dim; i++)
    {
      Argument *a = (Argument *)arguments->data[i];
      if (i)
          buf->writestring(", ");
      if (a->storageClass & STCref)
          buf->writestring((global.params.Dversion == 1)
            ? (char*)"inout " : (char*)"ref ");
      if (a->type)
          a->type->toCBuffer(buf, a->ident, hgs);
      else
          buf->writestring(a->ident->toChars());
    }
    buf->writestring("; ");
    aggr->toCBuffer(buf, hgs);
    buf->writebyte(')');
    buf->writenl();
    buf->writebyte('{');
    buf->writenl();
    if (body)
      body->toCBuffer(buf, hgs);
    buf->writebyte('}');
    buf->writenl();
}

/******************************** IfStatement ***************************/

IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
    : Statement(loc)
{
    this->arg = arg;
    this->condition = condition;
    this->ifbody = ifbody;
    this->elsebody = elsebody;
    this->match = NULL;
}

Statement *IfStatement::syntaxCopy()
{
    Statement *i = NULL;
    if (ifbody)
        i = ifbody->syntaxCopy();

    Statement *e = NULL;
    if (elsebody)
      e = elsebody->syntaxCopy();

    Argument *a = arg ? arg->syntaxCopy() : NULL;
    IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
    return s;
}

Statement *IfStatement::semantic(Scope *sc)
{
    condition = condition->semantic(sc);
    condition = resolveProperties(sc, condition);
    condition = condition->checkToBoolean();

    // If we can short-circuit evaluate the if statement, don't do the
    // semantic analysis of the skipped code.
    // This feature allows a limited form of conditional compilation.
    condition = condition->optimize(WANTflags);

    // Evaluate at runtime
    unsigned cs0 = sc->callSuper;
    unsigned cs1;

    Scope *scd;
    if (arg)
    { /* Declare arg, which we will set to be the
       * result of condition.
       */
      ScopeDsymbol *sym = new ScopeDsymbol();
      sym->parent = sc->scopesym;
      scd = sc->push(sym);

      Type *t = arg->type ? arg->type : condition->type;
      match = new VarDeclaration(loc, t, arg->ident, NULL);
      match->noscope = 1;
      match->semantic(scd);
      if (!scd->insert(match))
          assert(0);
      match->parent = sc->func;

      /* Generate:
       *  (arg = condition)
       */
      VarExp *v = new VarExp(0, match);
      condition = new AssignExp(loc, v, condition);
      condition = condition->semantic(scd);
    }
    else
      scd = sc->push();
    ifbody = ifbody->semantic(scd);
    scd->pop();

    cs1 = sc->callSuper;
    sc->callSuper = cs0;
    if (elsebody)
      elsebody = elsebody->semanticScope(sc, NULL, NULL);
    sc->mergeCallSuper(loc, cs1);

    return this;
}

int IfStatement::usesEH()
{
    return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
}

int IfStatement::blockExit()
{
    //printf("IfStatement::blockExit(%p)\n", this);

    int result = BEnone;
    if (condition->canThrow())
      result |= BEthrow;
    if (condition->isBool(TRUE))
    {
      if (ifbody)
          result |= ifbody->blockExit();
      else
          result |= BEfallthru;
    }
    else if (condition->isBool(FALSE))
    {
      if (elsebody)
          result |= elsebody->blockExit();
      else
          result |= BEfallthru;
    }
    else
    {
      if (ifbody)
          result |= ifbody->blockExit();
      else
          result |= BEfallthru;
      if (elsebody)
          result |= elsebody->blockExit();
      else
          result |= BEfallthru;
    }
    //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
    return result;
}

void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("if (");
    if (arg)
    {
      if (arg->type)
          arg->type->toCBuffer(buf, arg->ident, hgs);
      else
      {   buf->writestring("auto ");
          buf->writestring(arg->ident->toChars());
      }
      buf->writestring(" = ");
    }
    condition->toCBuffer(buf, hgs);
    buf->writebyte(')');
    buf->writenl();
    ifbody->toCBuffer(buf, hgs);
    if (elsebody)
    {   buf->writestring("else");
        buf->writenl();
        elsebody->toCBuffer(buf, hgs);
    }
}

/******************************** ConditionalStatement ***************************/

ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
    : Statement(loc)
{
    this->condition = condition;
    this->ifbody = ifbody;
    this->elsebody = elsebody;
}

Statement *ConditionalStatement::syntaxCopy()
{
    Statement *e = NULL;
    if (elsebody)
      e = elsebody->syntaxCopy();
    ConditionalStatement *s = new ConditionalStatement(loc,
            condition->syntaxCopy(), ifbody->syntaxCopy(), e);
    return s;
}

Statement *ConditionalStatement::semantic(Scope *sc)
{
    //printf("ConditionalStatement::semantic()\n");

    // If we can short-circuit evaluate the if statement, don't do the
    // semantic analysis of the skipped code.
    // This feature allows a limited form of conditional compilation.
    if (condition->include(sc, NULL))
    {
      ifbody = ifbody->semantic(sc);
      return ifbody;
    }
    else
    {
      if (elsebody)
          elsebody = elsebody->semantic(sc);
      return elsebody;
    }
}

Statements *ConditionalStatement::flatten(Scope *sc)
{
    Statement *s;

    if (condition->include(sc, NULL))
      s = ifbody;
    else
      s = elsebody;

    Statements *a = new Statements();
    a->push(s);
    return a;
}

int ConditionalStatement::usesEH()
{
    return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
}

int ConditionalStatement::blockExit()
{
    int result = ifbody->blockExit();
    if (elsebody)
      result |= elsebody->blockExit();
    return result;
}

void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    condition->toCBuffer(buf, hgs);
    buf->writenl();
    buf->writeByte('{');
    buf->writenl();
    if (ifbody)
      ifbody->toCBuffer(buf, hgs);
    buf->writeByte('}');
    buf->writenl();
    if (elsebody)
    {
      buf->writestring("else");
      buf->writenl();
      buf->writeByte('{');
      buf->writenl();
      elsebody->toCBuffer(buf, hgs);
      buf->writeByte('}');
      buf->writenl();
    }
    buf->writenl();
}


/******************************** PragmaStatement ***************************/

PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
    : Statement(loc)
{
    this->ident = ident;
    this->args = args;
    this->body = body;
}

Statement *PragmaStatement::syntaxCopy()
{
    Statement *b = NULL;
    if (body)
      b = body->syntaxCopy();
    PragmaStatement *s = new PragmaStatement(loc,
            ident, Expression::arraySyntaxCopy(args), b);
    return s;
}

Statement *PragmaStatement::semantic(Scope *sc)
{   // Should be merged with PragmaDeclaration
    //printf("PragmaStatement::semantic() %s\n", toChars());
    //printf("body = %p\n", body);
    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");
        }
    }
    else if (ident == Id::lib)
    {
#if 1
      /* Should this be allowed?
       */
      error("pragma(lib) not allowed as statement");
#else
      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);
          }
      }
#endif
    }

    // LDC
    else if (ident == Id::allow_inline)
    {
        sc->func->allowInlining = true;
    }

    else
        error("unrecognized pragma(%s)", ident->toChars());

    if (body)
    {
      body = body->semantic(sc);
    }
    return body;
}

int PragmaStatement::usesEH()
{
    return body && body->usesEH();
}

int PragmaStatement::blockExit()
{
    int result = BEfallthru;
#if 0 // currently, no code is generated for Pragma's, so it's just fallthru
    if (arrayExpressionCanThrow(args))
      result |= BEthrow;
    if (body)
      result |= body->blockExit();
#endif
    return result;
}

void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("pragma (");
    buf->writestring(ident->toChars());
    if (args && args->dim)
    {
      buf->writestring(", ");
      argsToCBuffer(buf, args, hgs);
    }
    buf->writeByte(')');
    if (body)
    {
      buf->writenl();
      buf->writeByte('{');
      buf->writenl();

      body->toCBuffer(buf, hgs);

      buf->writeByte('}');
      buf->writenl();
    }
    else
    {
      buf->writeByte(';');
      buf->writenl();
    }
}


/******************************** StaticAssertStatement ***************************/

StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
    : Statement(sa->loc)
{
    this->sa = sa;
}

Statement *StaticAssertStatement::syntaxCopy()
{
    StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
    return s;
}

Statement *StaticAssertStatement::semantic(Scope *sc)
{
    sa->semantic2(sc);
    return NULL;
}

void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    sa->toCBuffer(buf, hgs);
}


/******************************** SwitchStatement ***************************/

SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
    : Statement(loc)
{
    condition = c;
    body = b;
    sdefault = NULL;
    cases = NULL;
    hasNoDefault = 0;
    // LDC
    enclosingScopeExit = NULL;
}

Statement *SwitchStatement::syntaxCopy()
{
    SwitchStatement *s = new SwitchStatement(loc,
      condition->syntaxCopy(), body->syntaxCopy());
    return s;
}

Statement *SwitchStatement::semantic(Scope *sc)
{
    //printf("SwitchStatement::semantic(%p)\n", this);
    assert(!cases);           // ensure semantic() is only run once

    // LDC
    enclosingScopeExit = sc->enclosingScopeExit;

    condition = condition->semantic(sc);
    condition = resolveProperties(sc, condition);
    if (condition->type->isString())
    {
      // If it's not an array, cast it to one
      if (condition->type->ty != Tarray)
      {
          condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
      }
    }
    else
    { condition = condition->integralPromotions(sc);
      condition->checkIntegral();
    }
    condition = condition->optimize(WANTvalue);

    sc = sc->push();
    sc->sbreak = this;
    sc->sw = this;

    cases = new Array();
    sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
    body = body->semantic(sc);
    sc->noctor--;

    // Resolve any goto case's with exp
    for (int i = 0; i < gotoCases.dim; i++)
    {
      GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];

      if (!gcs->exp)
      {
          gcs->error("no case statement following goto case;");
          break;
      }

      for (Scope *scx = sc; scx; scx = scx->enclosing)
      {
          if (!scx->sw)
            continue;
          for (int j = 0; j < scx->sw->cases->dim; j++)
          {
            CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];

            if (cs->exp->equals(gcs->exp))
            {
                gcs->cs = cs;
                goto Lfoundcase;
            }
          }
      }
      gcs->error("case %s not found", gcs->exp->toChars());

     Lfoundcase:
      ;
    }

    if (!sc->sw->sdefault)
    { hasNoDefault = 1;

      warning("switch statement has no default");

      // Generate runtime error if the default is hit
      Statements *a = new Statements();
      CompoundStatement *cs;
      Statement *s;

      if (global.params.useSwitchError)
          s = new SwitchErrorStatement(loc);
      else
      {   Expression *e = new HaltExp(loc);
          s = new ExpStatement(loc, e);
      }

      a->reserve(4);
      a->push(body);

      // LDC needs semantic to be run on break
      Statement *breakstmt = new BreakStatement(loc, NULL);
      breakstmt->semantic(sc);
      a->push(breakstmt);

      sc->sw->sdefault = new DefaultStatement(loc, s);
      a->push(sc->sw->sdefault);
      cs = new CompoundStatement(loc, a);
      body = cs;
    }

    sc->pop();
    return this;
}

int SwitchStatement::hasBreak()
{
    return TRUE;
}

int SwitchStatement::usesEH()
{
    return body ? body->usesEH() : 0;
}

int SwitchStatement::blockExit()
{   int result = BEnone;
    if (condition->canThrow())
      result |= BEthrow;

    if (body)
    { result |= body->blockExit();
      if (result & BEbreak)
      {   result |= BEfallthru;
          result &= ~BEbreak;
      }
    }
    else
      result |= BEfallthru;

    return result;
}

void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("switch (");
    condition->toCBuffer(buf, hgs);
    buf->writebyte(')');
    buf->writenl();
    if (body)
    {
      if (!body->isScopeStatement())
        {   buf->writebyte('{');
            buf->writenl();
            body->toCBuffer(buf, hgs);
            buf->writebyte('}');
            buf->writenl();
        }
        else
        {
            body->toCBuffer(buf, hgs);
        }
    }
}

/******************************** CaseStatement ***************************/

CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
    : Statement(loc)
{
    this->exp = exp;
    this->statement = s;
    cblock = NULL;
    bodyBB = NULL;
    llvmIdx = NULL;
    // LDC
    enclosingScopeExit = NULL;
}

Statement *CaseStatement::syntaxCopy()
{
    CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
    return s;
}

Statement *CaseStatement::semantic(Scope *sc)
{   SwitchStatement *sw = sc->sw;

    //printf("CaseStatement::semantic() %s\n", toChars());
    
    exp = exp->semantic(sc);
    if (sw)
    {
      // LDC
      enclosingScopeExit = sc->enclosingScopeExit;
      if (enclosingScopeExit != sw->enclosingScopeExit)
      {
          error("case must be inside the same try, synchronized or volatile level as switch");
      }

      exp = exp->implicitCastTo(sc, sw->condition->type);
      exp = exp->optimize(WANTvalue | WANTinterpret);
      if (exp->op != TOKstring && exp->op != TOKint64)
      {
          error("case must be a string or an integral constant, not %s", exp->toChars());
          exp = new IntegerExp(0);
      }

      for (int i = 0; i < sw->cases->dim; i++)
      {
          CaseStatement *cs = (CaseStatement *)sw->cases->data[i];

          //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
          if (cs->exp->equals(exp))
          { error("duplicate case %s in switch statement", exp->toChars());
            break;
          }
      }

      sw->cases->push(this);

      // Resolve any goto case's with no exp to this case statement
      for (size_t i = 0; i < sw->gotoCases.dim; i++)
      {
          GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];

          if (!gcs->exp)
          {
            gcs->cs = this;
            sw->gotoCases.remove(i);      // remove from array
          }
      }
    }
    else
      error("case not in switch statement");
    statement = statement->semantic(sc);
    return this;
}

int CaseStatement::compare(Object *obj)
{
    // Sort cases so we can do an efficient lookup
    CaseStatement *cs2 = (CaseStatement *)(obj);

    return exp->compare(cs2->exp);
}

int CaseStatement::usesEH()
{
    return statement->usesEH();
}

int CaseStatement::blockExit()
{
    return statement->blockExit();
}

int CaseStatement::comeFrom()
{
    return TRUE;
}

void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("case ");
    exp->toCBuffer(buf, hgs);
    buf->writebyte(':');
    buf->writenl();
    statement->toCBuffer(buf, hgs);
}

/******************************** DefaultStatement ***************************/

DefaultStatement::DefaultStatement(Loc loc, Statement *s)
    : Statement(loc)
{
    this->statement = s;
#if IN_GCC
+    cblock = NULL;
#endif
    bodyBB = NULL;
    // LDC
    enclosingScopeExit = NULL;
}

Statement *DefaultStatement::syntaxCopy()
{
    DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
    return s;
}

Statement *DefaultStatement::semantic(Scope *sc)
{
    //printf("DefaultStatement::semantic()\n");

    if (sc->sw)
    {
      if (sc->sw->sdefault)
      {
          error("switch statement already has a default");
      }
      sc->sw->sdefault = this;

      // LDC
      enclosingScopeExit = sc->enclosingScopeExit;
      if (enclosingScopeExit != sc->sw->enclosingScopeExit)
      {
          error("default must be inside the same try, synchronized or volatile level as switch");
      }
    }
    else
      error("default not in switch statement");
    statement = statement->semantic(sc);
    return this;
}

int DefaultStatement::usesEH()
{
    return statement->usesEH();
}

int DefaultStatement::blockExit()
{
    return statement->blockExit();
}

int DefaultStatement::comeFrom()
{
    return TRUE;
}

void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("default:\n");
    statement->toCBuffer(buf, hgs);
}

/******************************** GotoDefaultStatement ***************************/

GotoDefaultStatement::GotoDefaultStatement(Loc loc)
    : Statement(loc)
{
    sw = NULL;
}

Statement *GotoDefaultStatement::syntaxCopy()
{
    GotoDefaultStatement *s = new GotoDefaultStatement(loc);
    return s;
}

Statement *GotoDefaultStatement::semantic(Scope *sc)
{
    sw = sc->sw;
    if (!sw)
      error("goto default not in switch statement");
    return this;
}

int GotoDefaultStatement::blockExit()
{
    return BEgoto;
}

void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("goto default;\n");
}

/******************************** GotoCaseStatement ***************************/

GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
    : Statement(loc)
{
    cs = NULL;
    this->exp = exp;
    sw = NULL;
}

Statement *GotoCaseStatement::syntaxCopy()
{
    Expression *e = exp ? exp->syntaxCopy() : NULL;
    GotoCaseStatement *s = new GotoCaseStatement(loc, e);
    return s;
}

Statement *GotoCaseStatement::semantic(Scope *sc)
{
    if (exp)
      exp = exp->semantic(sc);

    if (!sc->sw)
      error("goto case not in switch statement");
    else
    {
      sw = sc->sw;
      sc->sw->gotoCases.push(this);
      if (exp)
      {
          exp = exp->implicitCastTo(sc, sc->sw->condition->type);
          exp = exp->optimize(WANTvalue);
      }
    }
    return this;
}

int GotoCaseStatement::blockExit()
{
    return BEgoto;
}

void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("goto case");
    if (exp)
    {   buf->writebyte(' ');
        exp->toCBuffer(buf, hgs);
    }
    buf->writebyte(';');
    buf->writenl();
}

/******************************** SwitchErrorStatement ***************************/

SwitchErrorStatement::SwitchErrorStatement(Loc loc)
    : Statement(loc)
{
}

int SwitchErrorStatement::blockExit()
{
    return BEthrow;
}

void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("SwitchErrorStatement::toCBuffer()");
    buf->writenl();
}

/******************************** ReturnStatement ***************************/

ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
    : Statement(loc)
{
    this->exp = exp;
}

Statement *ReturnStatement::syntaxCopy()
{
    Expression *e = NULL;
    if (exp)
      e = exp->syntaxCopy();
    ReturnStatement *s = new ReturnStatement(loc, e);
    return s;
}

Statement *ReturnStatement::semantic(Scope *sc)
{
    //printf("ReturnStatement::semantic() %s\n", toChars());

    FuncDeclaration *fd = sc->parent->isFuncDeclaration();
    Scope *scx = sc;
    int implicit0 = 0;

    if (sc->fes)
    {
      // Find scope of function foreach is in
      for (; 1; scx = scx->enclosing)
      {
          assert(scx);
          if (scx->func != fd)
          { fd = scx->func;         // fd is now function enclosing foreach
            break;
          }
      }
    }

    Type *tret = fd->type->nextOf();
    if (fd->tintro)
      /* We'll be implicitly casting the return expression to tintro
       */
      tret = fd->tintro->nextOf();
    Type *tbret = NULL;

    if (tret)
      tbret = tret->toBasetype();

    // main() returns 0, even if it returns void
    if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
    { implicit0 = 1;
      exp = new IntegerExp(0);
    }

    if (sc->incontract || scx->incontract)
      error("return statements cannot be in contracts");
    if (sc->enclosingFinally || scx->enclosingFinally)
      error("return statements cannot be in finally, scope(exit) or scope(success) bodies");

    if (fd->isCtorDeclaration())
    {
      // Constructors implicitly do:
      //    return this;
      if (exp && exp->op != TOKthis)
          error("cannot return expression from constructor");
      exp = new ThisExp(0);
    }

    if (!exp)
      fd->nrvo_can = 0;

    if (exp)
    {
      fd->hasReturnExp |= 1;

      exp = exp->semantic(sc);
      exp = resolveProperties(sc, exp);
      exp = exp->optimize(WANTvalue);

      if (fd->nrvo_can && exp->op == TOKvar)
      {   VarExp *ve = (VarExp *)exp;
          VarDeclaration *v = ve->var->isVarDeclaration();

          if (!v || v->isOut() || v->isRef())
            fd->nrvo_can = 0;
          else if (fd->nrvo_var == NULL)
          { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
                fd->nrvo_var = v;
            else
                fd->nrvo_can = 0;
          }
          else if (fd->nrvo_var != v)
            fd->nrvo_can = 0;
      }
      else
          fd->nrvo_can = 0;

      if (fd->returnLabel && tbret->ty != Tvoid)
      {
      }
      else if (fd->inferRetType)
      {
          if (fd->type->nextOf())
          {
            if (!exp->type->equals(fd->type->nextOf()))
                error("mismatched function return type inference of %s and %s",
                  exp->type->toChars(), fd->type->nextOf()->toChars());
          }
          else
          {
            fd->type->next = exp->type;
            fd->type = fd->type->semantic(loc, sc);
            if (!fd->tintro)
            {   tret = fd->type->nextOf();
                tbret = tret->toBasetype();
            }
          }
      }
      else if (tbret->ty != Tvoid)
      {
          exp = exp->implicitCastTo(sc, tret);
      }
    }
    else if (fd->inferRetType)
    {
      if (fd->type->nextOf())
      {
          if (fd->type->nextOf()->ty != Tvoid)
            error("mismatched function return type inference of void and %s",
                fd->type->nextOf()->toChars());
      }
      else
      {
          fd->type->next = Type::tvoid;
          fd->type = fd->type->semantic(loc, sc);
          if (!fd->tintro)
          {   tret = Type::tvoid;
            tbret = tret;
          }
      }
    }
    else if (tbret->ty != Tvoid)    // if non-void return
      error("return expression expected");

    if (sc->fes)
    {
      Statement *s;

      if (exp && !implicit0)
      {
          exp = exp->implicitCastTo(sc, tret);
      }
      if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
          exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
          exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
          exp->op == TOKstring)
      {
          sc->fes->cases.push(this);
          // Construct: return cases.dim+1;
          s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
      }
      else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
      {
          s = new ReturnStatement(0, NULL);
          sc->fes->cases.push(s);

          // Construct: { exp; return cases.dim + 1; }
          Statement *s1 = new ExpStatement(loc, exp);
          Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
          s = new CompoundStatement(loc, s1, s2);
      }
      else
      {
          // Construct: return vresult;
          if (!fd->vresult)
          { // Declare vresult
            VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL);
            v->noscope = 1;
            v->semantic(scx);
            if (!scx->insert(v))
                assert(0);
            v->parent = fd;
            fd->vresult = v;
          }

          s = new ReturnStatement(0, new VarExp(0, fd->vresult));
          sc->fes->cases.push(s);

          // Construct: { vresult = exp; return cases.dim + 1; }
          exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp);
          exp = exp->semantic(sc);
          Statement *s1 = new ExpStatement(loc, exp);
          Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
          s = new CompoundStatement(loc, s1, s2);
      }
      return s;
    }

    if (exp)
    {
      if (fd->returnLabel && tbret->ty != Tvoid)
      {
          assert(fd->vresult);
          VarExp *v = new VarExp(0, fd->vresult);

          exp = new AssignExp(loc, v, exp);
          exp = exp->semantic(sc);
      }
      //exp->dump(0);
      //exp->print();
      exp->checkEscape();
    }

    /* BUG: need to issue an error on:
     *      this
     *      {   if (x) return;
     *          super();
     *      }
     */

    if (sc->callSuper & CSXany_ctor &&
      !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
      error("return without calling constructor");

    sc->callSuper |= CSXreturn;

    // See if all returns are instead to be replaced with a goto returnLabel;
    if (fd->returnLabel)
    {
      GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);

      gs->label = fd->returnLabel;
      if (exp)
      {   /* Replace: return exp;
           * with:    exp; goto returnLabel;
           */
          Statement *s = new ExpStatement(0, exp);
          return new CompoundStatement(loc, s, gs);
      }
      return gs;
    }

    if (exp && tbret->ty == Tvoid && !fd->isMain())
    {
      /* Replace:
       *    return exp;
       * with:
       *    exp; return;
       */
      Statement *s = new ExpStatement(loc, exp);
      loc = 0;
      exp = NULL;
      return new CompoundStatement(loc, s, this);
    }

    return this;
}

int ReturnStatement::blockExit()
{   int result = BEreturn;

    if (exp && exp->canThrow())
      result |= BEthrow;
    return result;
}

void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->printf("return ");
    if (exp)
      exp->toCBuffer(buf, hgs);
    buf->writeByte(';');
    buf->writenl();
}

/******************************** BreakStatement ***************************/

BreakStatement::BreakStatement(Loc loc, Identifier *ident)
    : Statement(loc)
{
    this->ident = ident;
}

Statement *BreakStatement::syntaxCopy()
{
    BreakStatement *s = new BreakStatement(loc, ident);
    return s;
}

Statement *BreakStatement::semantic(Scope *sc)
{
    //printf("BreakStatement::semantic()\n");
    // If:
    //      break Identifier;
    if (ident)
    {
      Scope *scx;
      FuncDeclaration *thisfunc = sc->func;

      for (scx = sc; scx; scx = scx->enclosing)
      {
          LabelStatement *ls;

          if (scx->func != thisfunc)      // if in enclosing function
          {
            if (sc->fes)            // if this is the body of a foreach
            {
                /* Post this statement to the fes, and replace
                 * it with a return value that caller will put into
                 * a switch. Caller will figure out where the break
                 * label actually is.
                 * Case numbers start with 2, not 0, as 0 is continue
                 * and 1 is break.
                 */
                Statement *s;
                sc->fes->cases.push(this);
                s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
                return s;
            }
            break;                  // can't break to it
          }

          ls = scx->slabel;
          if (ls && ls->ident == ident)
          {
            Statement *s = ls->statement;

            if (!s->hasBreak())
                error("label '%s' has no break", ident->toChars());
            if (ls->enclosingFinally != sc->enclosingFinally)
                error("cannot break out of finally block");
            
            this->target = ls;
            return this;
          }
      }
      error("enclosing label '%s' for break not found", ident->toChars());
    }
    else if (!sc->sbreak)
    {
      if (sc->fes)
      {   Statement *s;

          // Replace break; with return 1;
          s = new ReturnStatement(0, new IntegerExp(1));
          return s;
      }
      error("break is not inside a loop or switch");
    }
    return this;
}

int BreakStatement::blockExit()
{
    //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
    return ident ? BEgoto : BEbreak;
}

void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("break");
    if (ident)
    {   buf->writebyte(' ');
        buf->writestring(ident->toChars());
    }
    buf->writebyte(';');
    buf->writenl();
}

/******************************** ContinueStatement ***************************/

ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
    : Statement(loc)
{
    this->ident = ident;
}

Statement *ContinueStatement::syntaxCopy()
{
    ContinueStatement *s = new ContinueStatement(loc, ident);
    return s;
}

Statement *ContinueStatement::semantic(Scope *sc)
{
    //printf("ContinueStatement::semantic() %p\n", this);
    if (ident)
    {
      Scope *scx;
      FuncDeclaration *thisfunc = sc->func;

      for (scx = sc; scx; scx = scx->enclosing)
      {
          LabelStatement *ls;

          if (scx->func != thisfunc)      // if in enclosing function
          {
            if (sc->fes)            // if this is the body of a foreach
            {
                for (; scx; scx = scx->enclosing)
                {
                  ls = scx->slabel;
                  if (ls && ls->ident == ident && ls->statement == sc->fes)
                  {
                      // Replace continue ident; with return 0;
                      return new ReturnStatement(0, new IntegerExp(0));
                  }
                }

                /* Post this statement to the fes, and replace
                 * it with a return value that caller will put into
                 * a switch. Caller will figure out where the break
                 * label actually is.
                 * Case numbers start with 2, not 0, as 0 is continue
                 * and 1 is break.
                 */
                Statement *s;
                sc->fes->cases.push(this);
                s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
                return s;
            }
            break;                  // can't continue to it
          }

          ls = scx->slabel;
          if (ls && ls->ident == ident)
          {
            Statement *s = ls->statement;

            if (!s->hasContinue())
                error("label '%s' has no continue", ident->toChars());
            if (ls->enclosingFinally != sc->enclosingFinally)
                error("cannot continue out of finally block");
            
            this->target = ls;
            return this;
          }
      }
      error("enclosing label '%s' for continue not found", ident->toChars());
    }
    else if (!sc->scontinue)
    {
      if (sc->fes)
      {   Statement *s;

          // Replace continue; with return 0;
          s = new ReturnStatement(0, new IntegerExp(0));
          return s;
      }
      error("continue is not inside a loop");
    }
    return this;
}

int ContinueStatement::blockExit()
{
    return ident ? BEgoto : BEcontinue;
}

void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("continue");
    if (ident)
    {   buf->writebyte(' ');
        buf->writestring(ident->toChars());
    }
    buf->writebyte(';');
    buf->writenl();
}

/******************************** SynchronizedStatement ***************************/

SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
    : Statement(loc)
{
    this->exp = exp;
    this->body = body;
    this->esync = NULL;
    // LDC
    this->llsync = NULL;
}

SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
    : Statement(loc)
{
    this->exp = NULL;
    this->body = body;
    this->esync = esync;
    // LDC
    this->llsync = NULL;
}

Statement *SynchronizedStatement::syntaxCopy()
{
    Expression *e = exp ? exp->syntaxCopy() : NULL;
    SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
    return s;
}

Statement *SynchronizedStatement::semantic(Scope *sc)
{
    if (exp)
    { ClassDeclaration *cd;

      exp = exp->semantic(sc);
      exp = resolveProperties(sc, exp);
      cd = exp->type->isClassHandle();
      if (!cd)
          error("can only synchronize on class objects, not '%s'", exp->type->toChars());
      else if (cd->isInterfaceDeclaration())
      {   Type *t = new TypeIdentifier(0, Id::Object);

          t = t->semantic(0, sc);
          exp = new CastExp(loc, exp, t);
          exp = exp->semantic(sc);
      }
    }
    if (body)
    {
      Statement* oldScopeExit = sc->enclosingScopeExit;
      sc->enclosingScopeExit = this;
      body = body->semantic(sc);
      sc->enclosingScopeExit = oldScopeExit;
    }
    return this;
}

int SynchronizedStatement::hasBreak()
{
    return FALSE; //TRUE;
}

int SynchronizedStatement::hasContinue()
{
    return FALSE; //TRUE;
}

int SynchronizedStatement::usesEH()
{
    return TRUE;
}

int SynchronizedStatement::blockExit()
{
    return body ? body->blockExit() : BEfallthru;
}

void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("synchronized");
    if (exp)
    {   buf->writebyte('(');
      exp->toCBuffer(buf, hgs);
      buf->writebyte(')');
    }
    if (body)
    {
      buf->writebyte(' ');
      body->toCBuffer(buf, hgs);
    }
}

/******************************** WithStatement ***************************/

WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
    : Statement(loc)
{
    this->exp = exp;
    this->body = body;
    wthis = NULL;
}

Statement *WithStatement::syntaxCopy()
{
    WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
    return s;
}

Statement *WithStatement::semantic(Scope *sc)
{   ScopeDsymbol *sym;
    Initializer *init;

    //printf("WithStatement::semantic()\n");
    exp = exp->semantic(sc);
    exp = resolveProperties(sc, exp);
    if (exp->op == TOKimport)
    { ScopeExp *es = (ScopeExp *)exp;

      sym = es->sds;
    }
    else if (exp->op == TOKtype)
    { TypeExp *es = (TypeExp *)exp;

      sym = es->type->toDsymbol(sc)->isScopeDsymbol();
      if (!sym)
      {   error("%s has no members", es->toChars());
          body = body->semantic(sc);
          return this;
      }
    }
    else
    { Type *t = exp->type;

      assert(t);
      t = t->toBasetype();
      if (t->isClassHandle())
      {
          init = new ExpInitializer(loc, exp);
          wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
          wthis->semantic(sc);

          sym = new WithScopeSymbol(this);
          sym->parent = sc->scopesym;
      }
      else if (t->ty == Tstruct)
      {
          Expression *e = exp->addressOf(sc);
          init = new ExpInitializer(loc, e);
          wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
          wthis->semantic(sc);
          sym = new WithScopeSymbol(this);
          sym->parent = sc->scopesym;
      }
      else
      {   error("with expressions must be class objects, not '%s'", exp->type->toChars());
          return NULL;
      }
    }
    sc = sc->push(sym);

    if (body)
      body = body->semantic(sc);

    sc->pop();

    return this;
}

void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("with (");
    exp->toCBuffer(buf, hgs);
    buf->writestring(")\n");
    if (body)
      body->toCBuffer(buf, hgs);
}

int WithStatement::usesEH()
{
    return body ? body->usesEH() : 0;
}

int WithStatement::blockExit()
{
    int result = BEnone;
    if (exp->canThrow())
      result = BEthrow;
    if (body)
      result |= body->blockExit();
    else
      result |= BEfallthru;
    return result;
}

/******************************** TryCatchStatement ***************************/

TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
    : Statement(loc)
{
    this->body = body;
    this->catches = catches;
}

Statement *TryCatchStatement::syntaxCopy()
{
    Array *a = new Array();
    a->setDim(catches->dim);
    for (int i = 0; i < a->dim; i++)
    {   Catch *c;

      c = (Catch *)catches->data[i];
      c = c->syntaxCopy();
      a->data[i] = c;
    }
    TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
    return s;
}

Statement *TryCatchStatement::semantic(Scope *sc)
{
    body = body->semanticScope(sc, NULL /*this*/, NULL);

    /* Even if body is NULL, still do semantic analysis on catches
     */
    for (size_t i = 0; i < catches->dim; i++)
    {   Catch *c = (Catch *)catches->data[i];
      c->semantic(sc);

      // Determine if current catch 'hides' any previous catches
      for (size_t j = 0; j < i; j++)
      {   Catch *cj = (Catch *)catches->data[j];
          char *si = c->loc.toChars();
          char *sj = cj->loc.toChars();

          if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
            error("catch at %s hides catch at %s", sj, si);
      }
    }
    return this;
}

int TryCatchStatement::hasBreak()
{
    return FALSE; //TRUE;
}

int TryCatchStatement::usesEH()
{
    return TRUE;
}

int TryCatchStatement::blockExit()
{   int result;

    assert(body);
    result = body->blockExit();

    for (size_t i = 0; i < catches->dim; i++)
    {
        Catch *c = (Catch *)catches->data[i];
        result |= c->blockExit();
    }
    return result;
}

void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("try");
    buf->writenl();
    if (body)
        body->toCBuffer(buf, hgs);
    for (size_t i = 0; i < catches->dim; i++)
    {
        Catch *c = (Catch *)catches->data[i];
        c->toCBuffer(buf, hgs);
    }
}

/******************************** Catch ***************************/

Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
{
    //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
    this->loc = loc;
    this->type = t;
    this->ident = id;
    this->handler = handler;
    var = NULL;
}

Catch *Catch::syntaxCopy()
{
    Catch *c = new Catch(loc,
      (type ? type->syntaxCopy() : NULL),
      ident,
      (handler ? handler->syntaxCopy() : NULL));
    return c;
}

void Catch::semantic(Scope *sc)
{   ScopeDsymbol *sym;

    //printf("Catch::semantic(%s)\n", ident->toChars());

#ifndef IN_GCC
    if (sc->enclosingFinally)
    {
      /* This is because the _d_local_unwind() gets the stack munged
       * up on this. The workaround is to place any try-catches into
       * a separate function, and call that.
       * To fix, have the compiler automatically convert the finally
       * body into a nested function.
       */
      error(loc, "cannot put catch statement inside finally block");
    }
#endif

    sym = new ScopeDsymbol();
    sym->parent = sc->scopesym;
    sc = sc->push(sym);

    if (!type)
      type = new TypeIdentifier(0, Id::Object);
    type = type->semantic(loc, sc);
    if (!type->toBasetype()->isClassHandle())
      error("can only catch class objects, not '%s'", type->toChars());
    else if (ident)
    {
      var = new VarDeclaration(loc, type, ident, NULL);
      var->parent = sc->parent;
      sc->insert(var);
    }
    handler = handler->semantic(sc);

    sc->pop();
}

int Catch::blockExit()
{
    return handler ? handler->blockExit() : BEfallthru;
}

void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("catch");
    if (type)
    {   buf->writebyte('(');
      type->toCBuffer(buf, ident, hgs);
        buf->writebyte(')');
    }
    buf->writenl();
    buf->writebyte('{');
    buf->writenl();
    if (handler)
      handler->toCBuffer(buf, hgs);
    buf->writebyte('}');
    buf->writenl();
}

/****************************** TryFinallyStatement ***************************/

TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
    : Statement(loc)
{
    this->body = body;
    this->finalbody = finalbody;
}

Statement *TryFinallyStatement::syntaxCopy()
{
    TryFinallyStatement *s = new TryFinallyStatement(loc,
      body->syntaxCopy(), finalbody->syntaxCopy());
    return s;
}

Statement *TryFinallyStatement::semantic(Scope *sc)
{
    //printf("TryFinallyStatement::semantic()\n");

    Statement* oldScopeExit = sc->enclosingScopeExit;
    sc->enclosingScopeExit = this;
    body = body->semantic(sc);
    sc->enclosingScopeExit = oldScopeExit;

    sc = sc->push();
    sc->enclosingFinally = this;
    sc->sbreak = NULL;
    sc->scontinue = NULL;     // no break or continue out of finally block
    finalbody = finalbody->semantic(sc);
    sc->pop();
    return this;
}

void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->printf("try\n{\n");
    body->toCBuffer(buf, hgs);
    buf->printf("}\nfinally\n{\n");
    finalbody->toCBuffer(buf, hgs);
    buf->writeByte('}');
    buf->writenl();
}

int TryFinallyStatement::hasBreak()
{
    return FALSE; //TRUE;
}

int TryFinallyStatement::hasContinue()
{
    return FALSE; //TRUE;
}

int TryFinallyStatement::usesEH()
{
    return TRUE;
}

int TryFinallyStatement::blockExit()
{
    if (body)
      return body->blockExit();
    return BEfallthru;
}


/****************************** OnScopeStatement ***************************/

OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
    : Statement(loc)
{
    this->tok = tok;
    this->statement = statement;
}

Statement *OnScopeStatement::syntaxCopy()
{
    OnScopeStatement *s = new OnScopeStatement(loc,
      tok, statement->syntaxCopy());
    return s;
}

Statement *OnScopeStatement::semantic(Scope *sc)
{
    /* semantic is called on results of scopeCode() */
    return this;
}

int OnScopeStatement::blockExit()
{   // At this point, this statement is just an empty placeholder
    return BEfallthru;
}

void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring(Token::toChars(tok));
    buf->writebyte(' ');
    statement->toCBuffer(buf, hgs);
}

int OnScopeStatement::usesEH()
{
    return (tok != TOKon_scope_success);
}

void OnScopeStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
{
    //printf("OnScopeStatement::scopeCode()\n");
    //print();
    *sentry = NULL;
    *sexception = NULL;
    *sfinally = NULL;
    switch (tok)
    {
      case TOKon_scope_exit:
          *sfinally = statement;
          break;

      case TOKon_scope_failure:
          *sexception = statement;
          break;

      case TOKon_scope_success:
      {
          /* Create:
           *      sentry:   int x = 0;
           *      sexception:    x = 1;
           *      sfinally: if (!x) statement;
           */
          Identifier *id = Lexer::uniqueId("__os");

          ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
          VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
          *sentry = new DeclarationStatement(loc, v);

          Expression *e = new IntegerExp(1);
          e = new AssignExp(0, new VarExp(0, v), e);
          *sexception = new ExpStatement(0, e);

          e = new VarExp(0, v);
          e = new NotExp(0, e);
          *sfinally = new IfStatement(0, NULL, e, statement, NULL);

          break;
      }

      default:
          assert(0);
    }
}

/******************************** ThrowStatement ***************************/

ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
    : Statement(loc)
{
    this->exp = exp;
}

Statement *ThrowStatement::syntaxCopy()
{
    ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
    return s;
}

Statement *ThrowStatement::semantic(Scope *sc)
{
    //printf("ThrowStatement::semantic()\n");

    FuncDeclaration *fd = sc->parent->isFuncDeclaration();
    fd->hasReturnExp |= 2;

    if (sc->incontract)
      error("Throw statements cannot be in contracts");
    exp = exp->semantic(sc);
    exp = resolveProperties(sc, exp);
    if (!exp->type->toBasetype()->isClassHandle())
      error("can only throw class objects, not type %s", exp->type->toChars());
    return this;
}

int ThrowStatement::blockExit()
{
    return BEthrow;  // obviously
}

void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->printf("throw ");
    exp->toCBuffer(buf, hgs);
    buf->writeByte(';');
    buf->writenl();
}

/******************************** VolatileStatement **************************/

VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
    : Statement(loc)
{
    this->statement = statement;
}

Statement *VolatileStatement::syntaxCopy()
{
    VolatileStatement *s = new VolatileStatement(loc,
            statement ? statement->syntaxCopy() : NULL);
    return s;
}

Statement *VolatileStatement::semantic(Scope *sc)
{
    if (statement)
    {
      Statement* oldScopeExit = sc->enclosingScopeExit;
      sc->enclosingScopeExit = this;
      statement = statement->semantic(sc);
      sc->enclosingScopeExit = oldScopeExit;
    }
    return this;
}

Statements *VolatileStatement::flatten(Scope *sc)
{
    Statements *a;

    a = statement ? statement->flatten(sc) : NULL;
    if (a)
    { for (int i = 0; i < a->dim; i++)
      {   Statement *s = (Statement *)a->data[i];

          s = new VolatileStatement(loc, s);
          a->data[i] = s;
      }
    }

    return a;
}

int VolatileStatement::blockExit()
{
    return statement ? statement->blockExit() : BEfallthru;
}

void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("volatile");
    if (statement)
    {   if (statement->isScopeStatement())
            buf->writenl();
        else
            buf->writebyte(' ');
        statement->toCBuffer(buf, hgs);
    }
}


/******************************** GotoStatement ***************************/

GotoStatement::GotoStatement(Loc loc, Identifier *ident)
    : Statement(loc)
{
    this->ident = ident;
    this->label = NULL;
    this->enclosingFinally = NULL;
    this->enclosingScopeExit = NULL;
}

Statement *GotoStatement::syntaxCopy()
{
    GotoStatement *s = new GotoStatement(loc, ident);
    return s;
}

Statement *GotoStatement::semantic(Scope *sc)
{   FuncDeclaration *fd = sc->parent->isFuncDeclaration();

    //printf("GotoStatement::semantic()\n");
    enclosingFinally = sc->enclosingFinally;
    enclosingScopeExit = sc->enclosingScopeExit;

    label = fd->searchLabel(ident);
    if (!label->statement && sc->fes)
    {
      /* Either the goto label is forward referenced or it
       * is in the function that the enclosing foreach is in.
       * Can't know yet, so wrap the goto in a compound statement
       * so we can patch it later, and add it to a 'look at this later'
       * list.
       */
      Statements *a = new Statements();
      Statement *s;

      a->push(this);
      s = new CompoundStatement(loc, a);
      sc->fes->gotos.push(s);       // 'look at this later' list
      return s;
    }
    if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally)
      error("cannot goto in or out of finally block");
    return this;
}

int GotoStatement::blockExit()
{
    //printf("GotoStatement::blockExit(%p)\n", this);
    return BEgoto;
}

void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring("goto ");
    buf->writestring(ident->toChars());
    buf->writebyte(';');
    buf->writenl();
}

/******************************** LabelStatement ***************************/

LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
    : Statement(loc)
{
    this->ident = ident;
    this->statement = statement;
    this->enclosingFinally = NULL;
    this->enclosingScopeExit = NULL;
    this->lblock = NULL;
    this->isReturnLabel = 0;
    this->asmLabel = false;
}

Statement *LabelStatement::syntaxCopy()
{
    LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
    return s;
}

Statement *LabelStatement::semantic(Scope *sc)
{   LabelDsymbol *ls;
    FuncDeclaration *fd = sc->parent->isFuncDeclaration();

    //printf("LabelStatement::semantic()\n");
    ls = fd->searchLabel(ident);
    if (ls->statement)
      error("Label '%s' already defined", ls->toChars());
    else
      ls->statement = this;

    enclosingFinally = sc->enclosingFinally;
    enclosingScopeExit = sc->enclosingScopeExit;

    sc = sc->push();
    sc->scopesym = sc->enclosing->scopesym;
    sc->callSuper |= CSXlabel;
    sc->slabel = this;
    if (statement)
      statement = statement->semantic(sc);
    sc->pop();

    // LDC put in labmap
    fd->labmap[ident->toChars()] = this;

    return this;
}

Statements *LabelStatement::flatten(Scope *sc)
{
    Statements *a = NULL;

    if (statement)
    {
      a = statement->flatten(sc);
      if (a)
      {
          if (!a->dim)
          {
            a->push(new ExpStatement(loc, NULL));
          }
          Statement *s = (Statement *)a->data[0];

          s = new LabelStatement(loc, ident, s);
          a->data[0] = s;
      }
    }

    return a;
}


int LabelStatement::usesEH()
{
    return statement ? statement->usesEH() : FALSE;
}

int LabelStatement::blockExit()
{
    //printf("LabelStatement::blockExit(%p)\n", this);
    return statement ? statement->blockExit() : BEfallthru;
}

int LabelStatement::comeFrom()
{
    //printf("LabelStatement::comeFrom()\n");
    return TRUE;
}

void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring(ident->toChars());
    buf->writebyte(':');
    buf->writenl();
    if (statement)
        statement->toCBuffer(buf, hgs);
}


/******************************** LabelDsymbol ***************************/

LabelDsymbol::LabelDsymbol(Identifier *ident)
      : Dsymbol(ident)
{
    statement = NULL;
}

LabelDsymbol *LabelDsymbol::isLabel()           // is this a LabelDsymbol()?
{
    return this;
}

Generated by  Doxygen 1.6.0   Back to index