aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/expression.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/expression.c')
-rw-r--r--gcc/d/dmd/expression.c5706
1 files changed, 0 insertions, 5706 deletions
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
deleted file mode 100644
index 18aa6aa..0000000
--- a/gcc/d/dmd/expression.c
+++ /dev/null
@@ -1,5706 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/root.h"
-
-#include "errors.h"
-#include "mtype.h"
-#include "init.h"
-#include "expression.h"
-#include "template.h"
-#include "utf.h"
-#include "enum.h"
-#include "scope.h"
-#include "statement.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "import.h"
-#include "id.h"
-#include "dsymbol.h"
-#include "module.h"
-#include "attrib.h"
-#include "hdrgen.h"
-#include "parse.h"
-#include "doc.h"
-#include "root/aav.h"
-#include "nspace.h"
-#include "ctfe.h"
-#include "target.h"
-
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
-bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
-char *MODtoChars(MOD mod);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
-void toAutoQualChars(const char **result, Type *t1, Type *t2);
-
-/*****************************************
- * Determine if 'this' is available.
- * If it is, return the FuncDeclaration that has it.
- */
-
-FuncDeclaration *hasThis(Scope *sc)
-{
- //printf("hasThis()\n");
- Dsymbol *p = sc->parent;
- while (p && p->isTemplateMixin())
- p = p->parent;
- FuncDeclaration *fdthis = p ? p->isFuncDeclaration() : NULL;
- //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : "");
-
- // Go upwards until we find the enclosing member function
- FuncDeclaration *fd = fdthis;
- while (1)
- {
- if (!fd)
- {
- goto Lno;
- }
- if (!fd->isNested())
- break;
-
- Dsymbol *parent = fd->parent;
- while (1)
- {
- if (!parent)
- goto Lno;
- TemplateInstance *ti = parent->isTemplateInstance();
- if (ti)
- parent = ti->parent;
- else
- break;
- }
- fd = parent->isFuncDeclaration();
- }
-
- if (!fd->isThis())
- { //printf("test '%s'\n", fd->toChars());
- goto Lno;
- }
-
- assert(fd->vthis);
- return fd;
-
-Lno:
- return NULL; // don't have 'this' available
-}
-
-bool isNeedThisScope(Scope *sc, Declaration *d)
-{
- if (sc->intypeof == 1)
- return false;
-
- AggregateDeclaration *ad = d->isThis();
- if (!ad)
- return false;
- //printf("d = %s, ad = %s\n", d->toChars(), ad->toChars());
-
- for (Dsymbol *s = sc->parent; s; s = s->toParent2())
- {
- //printf("\ts = %s %s, toParent2() = %p\n", s->kind(), s->toChars(), s->toParent2());
- if (AggregateDeclaration *ad2 = s->isAggregateDeclaration())
- {
- if (ad2 == ad)
- return false;
- else if (ad2->isNested())
- continue;
- else
- return true;
- }
- if (FuncDeclaration *f = s->isFuncDeclaration())
- {
- if (f->isMember2())
- break;
- }
- }
- return true;
-}
-
-/******************************
- * check e is exp.opDispatch!(tiargs) or not
- * It's used to switch to UFCS the semantic analysis path
- */
-
-bool isDotOpDispatch(Expression *e)
-{
- return e->op == TOKdotti &&
- ((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch;
-}
-
-/****************************************
- * Expand tuples.
- * Input:
- * exps aray of Expressions
- * Output:
- * exps rewritten in place
- */
-
-void expandTuples(Expressions *exps)
-{
- //printf("expandTuples()\n");
- if (exps)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *arg = (*exps)[i];
- if (!arg)
- continue;
-
- // Look for tuple with 0 members
- if (arg->op == TOKtype)
- {
- TypeExp *e = (TypeExp *)arg;
- if (e->type->toBasetype()->ty == Ttuple)
- {
- TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
-
- if (!tt->arguments || tt->arguments->length == 0)
- {
- exps->remove(i);
- if (i == exps->length)
- return;
- i--;
- continue;
- }
- }
- }
-
- // Inline expand all the tuples
- while (arg->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)arg;
- exps->remove(i); // remove arg
- exps->insert(i, te->exps); // replace with tuple contents
- if (i == exps->length)
- return; // empty tuple, no more arguments
- (*exps)[i] = Expression::combine(te->e0, (*exps)[i]);
- arg = (*exps)[i];
- }
- }
- }
-}
-
-/****************************************
- * Expand alias this tuples.
- */
-
-TupleDeclaration *isAliasThisTuple(Expression *e)
-{
- if (!e->type)
- return NULL;
-
- Type *t = e->type->toBasetype();
-Lagain:
- if (Dsymbol *s = t->toDsymbol(NULL))
- {
- AggregateDeclaration *ad = s->isAggregateDeclaration();
- if (ad)
- {
- s = ad->aliasthis;
- if (s && s->isVarDeclaration())
- {
- TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration();
- if (td && td->isexp)
- return td;
- }
- if (Type *att = t->aliasthisOf())
- {
- t = att;
- goto Lagain;
- }
- }
- }
- return NULL;
-}
-
-int expandAliasThisTuples(Expressions *exps, size_t starti)
-{
- if (!exps || exps->length == 0)
- return -1;
-
- for (size_t u = starti; u < exps->length; u++)
- {
- Expression *exp = (*exps)[u];
- TupleDeclaration *td = isAliasThisTuple(exp);
- if (td)
- {
- exps->remove(u);
- for (size_t i = 0; i<td->objects->length; ++i)
- {
- Expression *e = isExpression((*td->objects)[i]);
- assert(e);
- assert(e->op == TOKdsymbol);
- DsymbolExp *se = (DsymbolExp *)e;
- Declaration *d = se->s->isDeclaration();
- assert(d);
- e = new DotVarExp(exp->loc, exp, d);
- assert(d->type);
- e->type = d->type;
- exps->insert(u + i, e);
- }
- return (int)u;
- }
- }
-
- return -1;
-}
-
-/****************************************
- * Get TemplateDeclaration enclosing FuncDeclaration.
- */
-
-TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s)
-{
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f && f->parent)
- {
- TemplateInstance *ti = f->parent->isTemplateInstance();
- if (ti && !ti->isTemplateMixin() &&
- ti->tempdecl && ((TemplateDeclaration *)ti->tempdecl)->onemember &&
- ti->tempdecl->ident == f->ident)
- {
- return (TemplateDeclaration *)ti->tempdecl;
- }
- }
- return NULL;
-}
-
-/************************************************
- * If we want the value of this expression, but do not want to call
- * the destructor on it.
- */
-
-Expression *valueNoDtor(Expression *e)
-{
- if (e->op == TOKcall)
- {
- /* The struct value returned from the function is transferred
- * so do not call the destructor on it.
- * Recognize:
- * ((S _ctmp = S.init), _ctmp).this(...)
- * and make sure the destructor is not called on _ctmp
- * BUG: if e is a CommaExp, we should go down the right side.
- */
- CallExp *ce = (CallExp *)e;
- if (ce->e1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)ce->e1;
- if (dve->var->isCtorDeclaration())
- {
- // It's a constructor call
- if (dve->e1->op == TOKcomma)
- {
- CommaExp *comma = (CommaExp *)dve->e1;
- if (comma->e2->op == TOKvar)
- {
- VarExp *ve = (VarExp *)comma->e2;
- VarDeclaration *ctmp = ve->var->isVarDeclaration();
- if (ctmp)
- {
- ctmp->storage_class |= STCnodtor;
- assert(!ce->isLvalue());
- }
- }
- }
- }
- }
- }
- else if (e->op == TOKvar)
- {
- VarDeclaration *vtmp = ((VarExp *)e)->var->isVarDeclaration();
- if (vtmp && vtmp->storage_class & STCrvalue)
- {
- vtmp->storage_class |= STCnodtor;
- }
- }
- return e;
-}
-
-/*********************************************
- * If e is an instance of a struct, and that struct has a copy constructor,
- * rewrite e as:
- * (tmp = e),tmp
- * Input:
- * sc just used to specify the scope of created temporary variable
- */
-Expression *callCpCtor(Scope *sc, Expression *e)
-{
- Type *tv = e->type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)tv)->sym;
- if (sd->postblit)
- {
- /* Create a variable tmp, and replace the argument e with:
- * (tmp = e),tmp
- * and let AssignExp() handle the construction.
- * This is not the most efficent, ideally tmp would be constructed
- * directly onto the stack.
- */
- VarDeclaration *tmp = copyToTemp(STCrvalue, "__copytmp", e);
- tmp->storage_class |= STCnodtor;
- dsymbolSemantic(tmp, sc);
- Expression *de = new DeclarationExp(e->loc, tmp);
- Expression *ve = new VarExp(e->loc, tmp);
- de->type = Type::tvoid;
- ve->type = e->type;
- e = Expression::combine(de, ve);
- }
- }
- return e;
-}
-
-/************************************************
- * Handle the postblit call on lvalue, or the move of rvalue.
- */
-Expression *doCopyOrMove(Scope *sc, Expression *e)
-{
- if (e->op == TOKquestion)
- {
- CondExp *ce = (CondExp *)e;
- ce->e1 = doCopyOrMove(sc, ce->e1);
- ce->e2 = doCopyOrMove(sc, ce->e2);
- }
- else
- {
- e = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
- }
- return e;
-}
-
-/******************************** Expression **************************/
-
-Expression::Expression(Loc loc, TOK op, int size)
-{
- //printf("Expression::Expression(op = %d) this = %p\n", op, this);
- this->loc = loc;
- this->op = op;
- this->size = (unsigned char)size;
- this->parens = 0;
- type = NULL;
-}
-
-void Expression::_init()
-{
- CTFEExp::cantexp = new CTFEExp(TOKcantexp);
- CTFEExp::voidexp = new CTFEExp(TOKvoidexp);
- CTFEExp::breakexp = new CTFEExp(TOKbreak);
- CTFEExp::continueexp = new CTFEExp(TOKcontinue);
- CTFEExp::gotoexp = new CTFEExp(TOKgoto);
-}
-
-Expression *Expression::syntaxCopy()
-{
- //printf("Expression::syntaxCopy()\n");
- //print();
- return copy();
-}
-
-/*********************************
- * Does *not* do a deep copy.
- */
-
-Expression *Expression::copy()
-{
- Expression *e;
- if (!size)
- {
- assert(0);
- }
- void *pe = mem.xmalloc(size);
- //printf("Expression::copy(op = %d) e = %p\n", op, pe);
- e = (Expression *)memcpy(pe, (void *)this, size);
- return e;
-}
-
-void Expression::print()
-{
- fprintf(stderr, "%s\n", toChars());
- fflush(stderr);
-}
-
-const char *Expression::toChars()
-{
- OutBuffer buf;
- HdrGenState hgs;
- toCBuffer(this, &buf, &hgs);
- return buf.extractChars();
-}
-
-void Expression::error(const char *format, ...) const
-{
- if (type != Type::terror)
- {
- va_list ap;
- va_start(ap, format);
- ::verror(loc, format, ap);
- va_end( ap );
- }
-}
-
-void Expression::warning(const char *format, ...) const
-{
- if (type != Type::terror)
- {
- va_list ap;
- va_start(ap, format);
- ::vwarning(loc, format, ap);
- va_end( ap );
- }
-}
-
-void Expression::deprecation(const char *format, ...) const
-{
- if (type != Type::terror)
- {
- va_list ap;
- va_start(ap, format);
- ::vdeprecation(loc, format, ap);
- va_end( ap );
- }
-}
-
-/**********************************
- * Combine e1 and e2 by CommaExp if both are not NULL.
- */
-Expression *Expression::combine(Expression *e1, Expression *e2)
-{
- if (e1)
- {
- if (e2)
- {
- e1 = new CommaExp(e1->loc, e1, e2);
- e1->type = e2->type;
- }
- }
- else
- e1 = e2;
- return e1;
-}
-
-/**********************************
- * If 'e' is a tree of commas, returns the leftmost expression
- * by stripping off it from the tree. The remained part of the tree
- * is returned via *pe0.
- * Otherwise 'e' is directly returned and *pe0 is set to NULL.
- */
-Expression *Expression::extractLast(Expression *e, Expression **pe0)
-{
- if (e->op != TOKcomma)
- {
- *pe0 = NULL;
- return e;
- }
-
- CommaExp *ce = (CommaExp *)e;
- if (ce->e2->op != TOKcomma)
- {
- *pe0 = ce->e1;
- return ce->e2;
- }
- else
- {
- *pe0 = e;
-
- Expression **pce = &ce->e2;
- while (((CommaExp *)(*pce))->e2->op == TOKcomma)
- {
- pce = &((CommaExp *)(*pce))->e2;
- }
- assert((*pce)->op == TOKcomma);
- ce = (CommaExp *)(*pce);
- *pce = ce->e1;
-
- return ce->e2;
- }
-}
-
-dinteger_t Expression::toInteger()
-{
- //printf("Expression %s\n", Token::toChars(op));
- error("integer constant expression expected instead of %s", toChars());
- return 0;
-}
-
-uinteger_t Expression::toUInteger()
-{
- //printf("Expression %s\n", Token::toChars(op));
- return (uinteger_t)toInteger();
-}
-
-real_t Expression::toReal()
-{
- error("floating point constant expression expected instead of %s", toChars());
- return CTFloat::zero;
-}
-
-real_t Expression::toImaginary()
-{
- error("floating point constant expression expected instead of %s", toChars());
- return CTFloat::zero;
-}
-
-complex_t Expression::toComplex()
-{
- error("floating point constant expression expected instead of %s", toChars());
- return complex_t(CTFloat::zero);
-}
-
-StringExp *Expression::toStringExp()
-{
- return NULL;
-}
-
-TupleExp *Expression::toTupleExp()
-{
- return NULL;
-}
-
-/***************************************
- * Return !=0 if expression is an lvalue.
- */
-
-bool Expression::isLvalue()
-{
- return false;
-}
-
-/*******************************
- * Give error if we're not an lvalue.
- * If we can, convert expression to be an lvalue.
- */
-
-Expression *Expression::toLvalue(Scope *, Expression *e)
-{
- if (!e)
- e = this;
- else if (!loc.filename)
- loc = e->loc;
-
- if (e->op == TOKtype)
- error("%s `%s` is a type, not an lvalue", e->type->kind(), e->type->toChars());
- else
- error("%s is not an lvalue", e->toChars());
-
- return new ErrorExp();
-}
-
-/***************************************
- * Parameters:
- * sc: scope
- * flag: 1: do not issue error message for invalid modification
- * Returns:
- * 0: is not modifiable
- * 1: is modifiable in default == being related to type->isMutable()
- * 2: is modifiable, because this is a part of initializing.
- */
-
-int Expression::checkModifiable(Scope *, int)
-{
- return type ? 1 : 0; // default modifiable
-}
-
-Expression *Expression::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars());
-
- // See if this expression is a modifiable lvalue (i.e. not const)
- if (checkModifiable(sc) == 1)
- {
- assert(type);
- if (!type->isMutable())
- {
- error("cannot modify %s expression %s", MODtoChars(type->mod), toChars());
- return new ErrorExp();
- }
- else if (!type->isAssignable())
- {
- error("cannot modify struct %s %s with immutable members", toChars(), type->toChars());
- return new ErrorExp();
- }
- }
- return toLvalue(sc, e);
-}
-
-/****************************************
- * Check that the expression has a valid type.
- * If not, generates an error "... has no type".
- * Returns:
- * true if the expression is not valid.
- * Note:
- * When this function returns true, `checkValue()` should also return true.
- */
-bool Expression::checkType()
-{
- return false;
-}
-
-/****************************************
- * Check that the expression has a valid value.
- * If not, generates an error "... has no value".
- * Returns:
- * true if the expression is not valid or has void type.
- */
-bool Expression::checkValue()
-{
- if (type && type->toBasetype()->ty == Tvoid)
- {
- error("expression %s is void and has no value", toChars());
- //print(); halt();
- if (!global.gag)
- type = Type::terror;
- return true;
- }
- return false;
-}
-
-bool Expression::checkScalar()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (!type->isscalar())
- {
- error("`%s` is not a scalar, it is a %s", toChars(), type->toChars());
- return true;
- }
- return checkValue();
-}
-
-bool Expression::checkNoBool()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (type->toBasetype()->ty == Tbool)
- {
- error("operation not allowed on bool `%s`", toChars());
- return true;
- }
- return false;
-}
-
-bool Expression::checkIntegral()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (!type->isintegral())
- {
- error("`%s` is not of integral type, it is a %s", toChars(), type->toChars());
- return true;
- }
- return checkValue();
-}
-
-bool Expression::checkArithmetic()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (!type->isintegral() && !type->isfloating())
- {
- error("`%s` is not of arithmetic type, it is a %s", toChars(), type->toChars());
- return true;
- }
- return checkValue();
-}
-
-bool Expression::checkDeprecated(Scope *sc, Dsymbol *s)
-{
- return s->checkDeprecated(loc, sc);
-}
-
-bool Expression::checkDisabled(Scope *sc, Dsymbol *s)
-{
- if (Declaration *d = s->isDeclaration())
- {
- return d->checkDisabled(loc, sc);
- }
- return false;
-}
-
-/*********************************************
- * Calling function f.
- * Check the purity, i.e. if we're in a pure function
- * we can only call other pure functions.
- * Returns true if error occurs.
- */
-bool Expression::checkPurity(Scope *sc, FuncDeclaration *f)
-{
- if (!sc->func)
- return false;
- if (sc->func == f)
- return false;
- if (sc->intypeof == 1)
- return false;
- if (sc->flags & (SCOPEctfe | SCOPEdebug))
- return false;
-
- /* Given:
- * void f() {
- * pure void g() {
- * /+pure+/ void h() {
- * /+pure+/ void i() { }
- * }
- * }
- * }
- * g() can call h() but not f()
- * i() can call h() and g() but not f()
- */
-
- // Find the closest pure parent of the calling function
- FuncDeclaration *outerfunc = sc->func;
- FuncDeclaration *calledparent = f;
-
- if (outerfunc->isInstantiated())
- {
- // The attributes of outerfunc should be inferred from the call of f.
- }
- else if (f->isInstantiated())
- {
- // The attributes of f are inferred from its body.
- }
- else if (f->isFuncLiteralDeclaration())
- {
- // The attributes of f are always inferred in its declared place.
- }
- else
- {
- /* Today, static local functions are impure by default, but they cannot
- * violate purity of enclosing functions.
- *
- * auto foo() pure { // non instantiated funciton
- * static auto bar() { // static, without pure attribute
- * impureFunc(); // impure call
- * // Although impureFunc is called inside bar, f(= impureFunc)
- * // is not callable inside pure outerfunc(= foo <- bar).
- * }
- *
- * bar();
- * // Although bar is called inside foo, f(= bar) is callable
- * // bacause calledparent(= foo) is same with outerfunc(= foo).
- * }
- */
-
- while (outerfunc->toParent2() &&
- outerfunc->isPureBypassingInference() == PUREimpure &&
- outerfunc->toParent2()->isFuncDeclaration())
- {
- outerfunc = outerfunc->toParent2()->isFuncDeclaration();
- if (outerfunc->type->ty == Terror)
- return true;
- }
- while (calledparent->toParent2() &&
- calledparent->isPureBypassingInference() == PUREimpure &&
- calledparent->toParent2()->isFuncDeclaration())
- {
- calledparent = calledparent->toParent2()->isFuncDeclaration();
- if (calledparent->type->ty == Terror)
- return true;
- }
- }
-
- // If the caller has a pure parent, then either the called func must be pure,
- // OR, they must have the same pure parent.
- if (!f->isPure() && calledparent != outerfunc)
- {
- FuncDeclaration *ff = outerfunc;
- if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
- {
- error("pure %s `%s` cannot call impure %s `%s`",
- ff->kind(), ff->toPrettyChars(), f->kind(), f->toPrettyChars());
- return true;
- }
- }
- return false;
-}
-
-/*******************************************
- * Accessing variable v.
- * Check for purity and safety violations.
- * Returns true if error occurs.
- */
-bool Expression::checkPurity(Scope *sc, VarDeclaration *v)
-{
- //printf("v = %s %s\n", v->type->toChars(), v->toChars());
-
- /* Look for purity and safety violations when accessing variable v
- * from current function.
- */
- if (!sc->func)
- return false;
- if (sc->intypeof == 1)
- return false; // allow violations inside typeof(expression)
- if (sc->flags & (SCOPEctfe | SCOPEdebug))
- return false; // allow violations inside compile-time evaluated expressions and debug conditionals
- if (v->ident == Id::ctfe)
- return false; // magic variable never violates pure and safe
- if (v->isImmutable())
- return false; // always safe and pure to access immutables...
- if (v->isConst() && !v->isRef() && (v->isDataseg() || v->isParameter()) &&
- v->type->implicitConvTo(v->type->immutableOf()))
- return false; // or const global/parameter values which have no mutable indirections
- if (v->storage_class & STCmanifest)
- return false; // ...or manifest constants
-
- bool err = false;
- if (v->isDataseg())
- {
- // Bugzilla 7533: Accessing implicit generated __gate is pure.
- if (v->ident == Id::gate)
- return false;
-
- /* Accessing global mutable state.
- * Therefore, this function and all its immediately enclosing
- * functions must be pure.
- */
- /* Today, static local functions are impure by default, but they cannot
- * violate purity of enclosing functions.
- *
- * auto foo() pure { // non instantiated funciton
- * static auto bar() { // static, without pure attribute
- * globalData++; // impure access
- * // Although globalData is accessed inside bar,
- * // it is not accessible inside pure foo.
- * }
- * }
- */
- for (Dsymbol *s = sc->func; s; s = s->toParent2())
- {
- FuncDeclaration *ff = s->isFuncDeclaration();
- if (!ff)
- break;
- if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
- {
- error("pure %s `%s` cannot access mutable static data `%s`",
- ff->kind(), ff->toPrettyChars(), v->toChars());
- err = true;
- break;
- }
- /* If the enclosing is an instantiated function or a lambda, its
- * attribute inference result is preferred.
- */
- if (ff->isInstantiated())
- break;
- if (ff->isFuncLiteralDeclaration())
- break;
- }
- }
- else
- {
- /* Given:
- * void f() {
- * int fx;
- * pure void g() {
- * int gx;
- * /+pure+/ void h() {
- * int hx;
- * /+pure+/ void i() { }
- * }
- * }
- * }
- * i() can modify hx and gx but not fx
- */
-
- Dsymbol *vparent = v->toParent2();
- for (Dsymbol *s = sc->func; !err && s; s = s->toParent2())
- {
- if (s == vparent)
- break;
-
- if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (ad->isNested())
- continue;
- break;
- }
- FuncDeclaration *ff = s->isFuncDeclaration();
- if (!ff)
- break;
- if (ff->isNested() || ff->isThis())
- {
- if (ff->type->isImmutable() ||
- (ff->type->isShared() && !MODimplicitConv(ff->type->mod, v->type->mod)))
- {
- OutBuffer ffbuf;
- OutBuffer vbuf;
- MODMatchToBuffer(&ffbuf, ff->type->mod, v->type->mod);
- MODMatchToBuffer(&vbuf, v->type->mod, ff->type->mod);
- error("%s%s `%s` cannot access %sdata `%s`",
- ffbuf.peekChars(), ff->kind(), ff->toPrettyChars(), vbuf.peekChars(), v->toChars());
- err = true;
- break;
- }
- continue;
- }
- break;
- }
- }
-
- /* Do not allow safe functions to access __gshared data
- */
- if (v->storage_class & STCgshared)
- {
- if (sc->func->setUnsafe())
- {
- error("safe %s `%s` cannot access __gshared data `%s`",
- sc->func->kind(), sc->func->toChars(), v->toChars());
- err = true;
- }
- }
-
- return err;
-}
-
-/*********************************************
- * Calling function f.
- * Check the safety, i.e. if we're in a @safe function
- * we can only call @safe or @trusted functions.
- * Returns true if error occurs.
- */
-bool Expression::checkSafety(Scope *sc, FuncDeclaration *f)
-{
- if (!sc->func)
- return false;
- if (sc->func == f)
- return false;
- if (sc->intypeof == 1)
- return false;
- if (sc->flags & SCOPEctfe)
- return false;
-
- if (!f->isSafe() && !f->isTrusted())
- {
- if (sc->flags & SCOPEcompile ? sc->func->isSafeBypassingInference() : sc->func->setUnsafe())
- {
- if (loc.linnum == 0) // e.g. implicitly generated dtor
- loc = sc->func->loc;
-
- error("@safe %s `%s` cannot call @system %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
- return true;
- }
- }
- return false;
-}
-
-/*********************************************
- * Calling function f.
- * Check the @nogc-ness, i.e. if we're in a @nogc function
- * we can only call other @nogc functions.
- * Returns true if error occurs.
- */
-bool Expression::checkNogc(Scope *sc, FuncDeclaration *f)
-{
- if (!sc->func)
- return false;
- if (sc->func == f)
- return false;
- if (sc->intypeof == 1)
- return false;
- if (sc->flags & SCOPEctfe)
- return false;
-
- if (!f->isNogc())
- {
- if (sc->flags & SCOPEcompile ? sc->func->isNogcBypassingInference() : sc->func->setGC())
- {
- if (loc.linnum == 0) // e.g. implicitly generated dtor
- loc = sc->func->loc;
-
- error("@nogc %s `%s` cannot call non-@nogc %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
- return true;
- }
- }
- return false;
-}
-
-/********************************************
- * Check that the postblit is callable if t is an array of structs.
- * Returns true if error happens.
- */
-bool Expression::checkPostblit(Scope *sc, Type *t)
-{
- t = t->baseElemOf();
- if (t->ty == Tstruct)
- {
- if (global.params.useTypeInfo && Type::dtypeinfo)
- {
- // Bugzilla 11395: Require TypeInfo generation for array concatenation
- semanticTypeInfo(sc, t);
- }
-
- StructDeclaration *sd = ((TypeStruct *)t)->sym;
- if (sd->postblit)
- {
- if (sd->postblit->checkDisabled(loc, sc))
- return true;
- //checkDeprecated(sc, sd->postblit); // necessary?
- checkPurity(sc, sd->postblit);
- checkSafety(sc, sd->postblit);
- checkNogc(sc, sd->postblit);
- //checkAccess(sd, loc, sc, sd->postblit); // necessary?
- return false;
- }
- }
- return false;
-}
-
-bool Expression::checkRightThis(Scope *sc)
-{
- if (op == TOKerror)
- return true;
- if (op == TOKvar && type->ty != Terror)
- {
- VarExp *ve = (VarExp *)this;
- if (isNeedThisScope(sc, ve->var))
- {
- //printf("checkRightThis sc->intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
- // sc->intypeof, sc->getStructClassScope(), func, fdthis);
- error("need `this` for `%s` of type `%s`", ve->var->toChars(), ve->var->type->toChars());
- return true;
- }
- }
- return false;
-}
-
-/*******************************
- * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
- * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
- * Returns true if error occurs.
- */
-bool Expression::checkReadModifyWrite(TOK rmwOp, Expression *ex)
-{
- //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex->toChars() : "");
- if (!type || !type->isShared())
- return false;
-
- // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
- switch (rmwOp)
- {
- case TOKplusplus:
- case TOKpreplusplus:
- rmwOp = TOKaddass;
- break;
-
- case TOKminusminus:
- case TOKpreminusminus:
- rmwOp = TOKminass;
- break;
-
- default:
- break;
- }
-
- deprecation("read-modify-write operations are not allowed for shared variables. "
- "Use core.atomic.atomicOp!\"%s\"(%s, %s) instead.",
- Token::tochars[rmwOp], toChars(), ex ? ex->toChars() : "1");
- return false;
-
- // note: enable when deprecation becomes an error.
- // return true;
-}
-
-/*****************************
- * If expression can be tested for true or false,
- * returns the modified expression.
- * Otherwise returns ErrorExp.
- */
-Expression *Expression::toBoolean(Scope *sc)
-{
- // Default is 'yes' - do nothing
- Expression *e = this;
- Type *t = type;
- Type *tb = type->toBasetype();
- Type *att = NULL;
-Lagain:
- // Structs can be converted to bool using opCast(bool)()
- if (tb->ty == Tstruct)
- {
- AggregateDeclaration *ad = ((TypeStruct *)tb)->sym;
- /* Don't really need to check for opCast first, but by doing so we
- * get better error messages if it isn't there.
- */
- Dsymbol *fd = search_function(ad, Id::_cast);
- if (fd)
- {
- e = new CastExp(loc, e, Type::tbool);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- // Forward to aliasthis.
- if (ad->aliasthis && tb != att)
- {
- if (!att && tb->checkAliasThisRec())
- att = tb;
- e = resolveAliasThis(sc, e);
- t = e->type;
- tb = e->type->toBasetype();
- goto Lagain;
- }
- }
-
- if (!t->isBoolean())
- {
- if (tb != Type::terror)
- error("expression %s of type %s does not have a boolean value", toChars(), t->toChars());
- return new ErrorExp();
- }
- return e;
-}
-
-/******************************
- * Take address of expression.
- */
-
-Expression *Expression::addressOf()
-{
- //printf("Expression::addressOf()\n");
- Expression *e = new AddrExp(loc, this);
- e->type = type->pointerTo();
- return e;
-}
-
-/******************************
- * If this is a reference, dereference it.
- */
-
-Expression *Expression::deref()
-{
- //printf("Expression::deref()\n");
- // type could be null if forward referencing an 'auto' variable
- if (type && type->ty == Treference)
- {
- Expression *e = new PtrExp(loc, this);
- e->type = ((TypeReference *)type)->next;
- return e;
- }
- return this;
-}
-
-/********************************
- * Does this expression statically evaluate to a boolean 'result' (true or false)?
- */
-bool Expression::isBool(bool)
-{
- return false;
-}
-
-IntegerExp *Expression::isIntegerExp()
-{
- return op == TOKint64 ? (IntegerExp *)this : NULL;
-}
-
-ErrorExp *Expression::isErrorExp()
-{
- return op == TOKerror ? (ErrorExp *)this : NULL;
-}
-
-VoidInitExp *Expression::isVoidInitExp()
-{
- return op == TOKvoid ? (VoidInitExp *)this : NULL;
-}
-
-RealExp *Expression::isRealExp()
-{
- return op == TOKfloat64 ? (RealExp *)this : NULL;
-}
-
-ComplexExp *Expression::isComplexExp()
-{
- return op == TOKcomplex80 ? (ComplexExp *)this : NULL;
-}
-
-IdentifierExp *Expression::isIdentifierExp()
-{
- return op == TOKidentifier ? (IdentifierExp *)this : NULL;
-}
-
-DollarExp *Expression::isDollarExp()
-{
- return op == TOKdollar ? (DollarExp *)this : NULL;
-}
-
-DsymbolExp *Expression::isDsymbolExp()
-{
- return op == TOKdsymbol ? (DsymbolExp *)this : NULL;
-}
-
-ThisExp *Expression::isThisExp()
-{
- return op == TOKthis ? (ThisExp *)this : NULL;
-}
-
-SuperExp *Expression::isSuperExp()
-{
- return op == TOKsuper ? (SuperExp *)this : NULL;
-}
-
-NullExp *Expression::isNullExp()
-{
- return op == TOKnull ? (NullExp *)this : NULL;
-}
-
-StringExp *Expression::isStringExp()
-{
- return op == TOKstring ? (StringExp *)this : NULL;
-}
-
-TupleExp *Expression::isTupleExp()
-{
- return op == TOKtuple ? (TupleExp *)this : NULL;
-}
-
-ArrayLiteralExp *Expression::isArrayLiteralExp()
-{
- return op == TOKarrayliteral ? (ArrayLiteralExp *)this : NULL;
-}
-
-AssocArrayLiteralExp *Expression::isAssocArrayLiteralExp()
-{
- return op == TOKassocarrayliteral ? (AssocArrayLiteralExp *)this : NULL;
-}
-
-StructLiteralExp *Expression::isStructLiteralExp()
-{
- return op == TOKstructliteral ? (StructLiteralExp *)this : NULL;
-}
-
-TypeExp *Expression::isTypeExp()
-{
- return op == TOKtype ? (TypeExp *)this : NULL;
-}
-
-ScopeExp *Expression::isScopeExp()
-{
- return op == TOKscope ? (ScopeExp *)this : NULL;
-}
-
-TemplateExp *Expression::isTemplateExp()
-{
- return op == TOKtemplate ? (TemplateExp *)this : NULL;
-}
-
-NewExp *Expression::isNewExp()
-{
- return op == TOKnew ? (NewExp *)this : NULL;
-}
-
-NewAnonClassExp *Expression::isNewAnonClassExp()
-{
- return op == TOKnewanonclass ? (NewAnonClassExp *)this : NULL;
-}
-
-SymOffExp *Expression::isSymOffExp()
-{
- return op == TOKsymoff ? (SymOffExp *)this : NULL;
-}
-
-VarExp *Expression::isVarExp()
-{
- return op == TOKvar ? (VarExp *)this : NULL;
-}
-
-OverExp *Expression::isOverExp()
-{
- return op == TOKoverloadset ? (OverExp *)this : NULL;
-}
-
-FuncExp *Expression::isFuncExp()
-{
- return op == TOKfunction ? (FuncExp *)this : NULL;
-}
-
-DeclarationExp *Expression::isDeclarationExp()
-{
- return op == TOKdeclaration ? (DeclarationExp *)this : NULL;
-}
-
-TypeidExp *Expression::isTypeidExp()
-{
- return op == TOKtypeid ? (TypeidExp *)this : NULL;
-}
-
-TraitsExp *Expression::isTraitsExp()
-{
- return op == TOKtraits ? (TraitsExp *)this : NULL;
-}
-
-HaltExp *Expression::isHaltExp()
-{
- return op == TOKhalt ? (HaltExp *)this : NULL;
-}
-
-IsExp *Expression::isExp()
-{
- return op == TOKis ? (IsExp *)this : NULL;
-}
-
-CompileExp *Expression::isCompileExp()
-{
- return op == TOKmixin ? (CompileExp *)this : NULL;
-}
-
-ImportExp *Expression::isImportExp()
-{
- return op == TOKimport ? (ImportExp *)this : NULL;
-}
-
-AssertExp *Expression::isAssertExp()
-{
- return op == TOKassert ? (AssertExp *)this : NULL;
-}
-
-DotIdExp *Expression::isDotIdExp()
-{
- return op == TOKdotid ? (DotIdExp *)this : NULL;
-}
-
-DotTemplateExp *Expression::isDotTemplateExp()
-{
- return op == TOKdotti ? (DotTemplateExp *)this : NULL;
-}
-
-DotVarExp *Expression::isDotVarExp()
-{
- return op == TOKdotvar ? (DotVarExp *)this : NULL;
-}
-
-DotTemplateInstanceExp *Expression::isDotTemplateInstanceExp()
-{
- return op == TOKdotti ? (DotTemplateInstanceExp *)this : NULL;
-}
-
-DelegateExp *Expression::isDelegateExp()
-{
- return op == TOKdelegate ? (DelegateExp *)this : NULL;
-}
-
-DotTypeExp *Expression::isDotTypeExp()
-{
- return op == TOKdottype ? (DotTypeExp *)this : NULL;
-}
-
-CallExp *Expression::isCallExp()
-{
- return op == TOKcall ? (CallExp *)this : NULL;
-}
-
-AddrExp *Expression::isAddrExp()
-{
- return op == TOKaddress ? (AddrExp *)this : NULL;
-}
-
-PtrExp *Expression::isPtrExp()
-{
- return op == TOKstar ? (PtrExp *)this : NULL;
-}
-
-NegExp *Expression::isNegExp()
-{
- return op == TOKneg ? (NegExp *)this : NULL;
-}
-
-UAddExp *Expression::isUAddExp()
-{
- return op == TOKuadd ? (UAddExp *)this : NULL;
-}
-
-ComExp *Expression::isComExp()
-{
- return op == TOKtilde ? (ComExp *)this : NULL;
-}
-
-NotExp *Expression::isNotExp()
-{
- return op == TOKnot ? (NotExp *)this : NULL;
-}
-
-DeleteExp *Expression::isDeleteExp()
-{
- return op == TOKdelete ? (DeleteExp *)this : NULL;
-}
-
-CastExp *Expression::isCastExp()
-{
- return op == TOKcast ? (CastExp *)this : NULL;
-}
-
-VectorExp *Expression::isVectorExp()
-{
- return op == TOKvector ? (VectorExp *)this : NULL;
-}
-
-VectorArrayExp *Expression::isVectorArrayExp()
-{
- return op == TOKvectorarray ? (VectorArrayExp *)this : NULL;
-}
-
-SliceExp *Expression::isSliceExp()
-{
- return op == TOKslice ? (SliceExp *)this : NULL;
-}
-
-ArrayLengthExp *Expression::isArrayLengthExp()
-{
- return op == TOKarraylength ? (ArrayLengthExp *)this : NULL;
-}
-
-ArrayExp *Expression::isArrayExp()
-{
- return op == TOKarray ? (ArrayExp *)this : NULL;
-}
-
-DotExp *Expression::isDotExp()
-{
- return op == TOKdot ? (DotExp *)this : NULL;
-}
-
-CommaExp *Expression::isCommaExp()
-{
- return op == TOKcomma ? (CommaExp *)this : NULL;
-}
-
-IntervalExp *Expression::isIntervalExp()
-{
- return op == TOKinterval ? (IntervalExp *)this : NULL;
-}
-
-DelegatePtrExp *Expression::isDelegatePtrExp()
-{
- return op == TOKdelegateptr ? (DelegatePtrExp *)this : NULL;
-}
-
-DelegateFuncptrExp *Expression::isDelegateFuncptrExp()
-{
- return op == TOKdelegatefuncptr ? (DelegateFuncptrExp *)this : NULL;
-}
-
-IndexExp *Expression::isIndexExp()
-{
- return op == TOKindex ? (IndexExp *)this : NULL;
-}
-
-PostExp *Expression::isPostExp()
-{
- return (op == TOKplusplus || op == TOKminusminus) ? (PostExp *)this : NULL;
-}
-
-PreExp *Expression::isPreExp()
-{
- return (op == TOKpreplusplus || op == TOKpreminusminus) ? (PreExp *)this : NULL;
-}
-
-AssignExp *Expression::isAssignExp()
-{
- return op == TOKassign ? (AssignExp *)this : NULL;
-}
-
-ConstructExp *Expression::isConstructExp()
-{
- return op == TOKconstruct ? (ConstructExp *)this : NULL;
-}
-
-BlitExp *Expression::isBlitExp()
-{
- return op == TOKblit ? (BlitExp *)this : NULL;
-}
-
-AddAssignExp *Expression::isAddAssignExp()
-{
- return op == TOKaddass ? (AddAssignExp *)this : NULL;
-}
-
-MinAssignExp *Expression::isMinAssignExp()
-{
- return op == TOKminass ? (MinAssignExp *)this : NULL;
-}
-
-MulAssignExp *Expression::isMulAssignExp()
-{
- return op == TOKmulass ? (MulAssignExp *)this : NULL;
-}
-
-
-DivAssignExp *Expression::isDivAssignExp()
-{
- return op == TOKdivass ? (DivAssignExp *)this : NULL;
-}
-
-ModAssignExp *Expression::isModAssignExp()
-{
- return op == TOKmodass ? (ModAssignExp *)this : NULL;
-}
-
-AndAssignExp *Expression::isAndAssignExp()
-{
- return op == TOKandass ? (AndAssignExp *)this : NULL;
-}
-
-OrAssignExp *Expression::isOrAssignExp()
-{
- return op == TOKorass ? (OrAssignExp *)this : NULL;
-}
-
-XorAssignExp *Expression::isXorAssignExp()
-{
- return op == TOKxorass ? (XorAssignExp *)this : NULL;
-}
-
-PowAssignExp *Expression::isPowAssignExp()
-{
- return op == TOKpowass ? (PowAssignExp *)this : NULL;
-}
-
-
-ShlAssignExp *Expression::isShlAssignExp()
-{
- return op == TOKshlass ? (ShlAssignExp *)this : NULL;
-}
-
-ShrAssignExp *Expression::isShrAssignExp()
-{
- return op == TOKshrass ? (ShrAssignExp *)this : NULL;
-}
-
-UshrAssignExp *Expression::isUshrAssignExp()
-{
- return op == TOKushrass ? (UshrAssignExp *)this : NULL;
-}
-
-CatAssignExp *Expression::isCatAssignExp()
-{
- return op == TOKcatass ? (CatAssignExp *)this : NULL;
-}
-
-AddExp *Expression::isAddExp()
-{
- return op == TOKadd ? (AddExp *)this : NULL;
-}
-
-MinExp *Expression::isMinExp()
-{
- return op == TOKmin ? (MinExp *)this : NULL;
-}
-
-CatExp *Expression::isCatExp()
-{
- return op == TOKcat ? (CatExp *)this : NULL;
-}
-
-MulExp *Expression::isMulExp()
-{
- return op == TOKmul ? (MulExp *)this : NULL;
-}
-
-DivExp *Expression::isDivExp()
-{
- return op == TOKdiv ? (DivExp *)this : NULL;
-}
-
-ModExp *Expression::isModExp()
-{
- return op == TOKmod ? (ModExp *)this : NULL;
-}
-
-PowExp *Expression::isPowExp()
-{
- return op == TOKpow ? (PowExp *)this : NULL;
-}
-
-ShlExp *Expression::isShlExp()
-{
- return op == TOKshl ? (ShlExp *)this : NULL;
-}
-
-ShrExp *Expression::isShrExp()
-{
- return op == TOKshr ? (ShrExp *)this : NULL;
-}
-
-UshrExp *Expression::isUshrExp()
-{
- return op == TOKushr ? (UshrExp *)this : NULL;
-}
-
-AndExp *Expression::isAndExp()
-{
- return op == TOKand ? (AndExp *)this : NULL;
-}
-
-OrExp *Expression::isOrExp()
-{
- return op == TOKor ? (OrExp *)this : NULL;
-}
-
-XorExp *Expression::isXorExp()
-{
- return op == TOKxor ? (XorExp *)this : NULL;
-}
-
-LogicalExp *Expression::isLogicalExp()
-{
- return (op == TOKandand || op == TOKoror) ? (LogicalExp *)this : NULL;
-}
-
-InExp *Expression::isInExp()
-{
- return op == TOKin ? (InExp *)this : NULL;
-}
-
-RemoveExp *Expression::isRemoveExp()
-{
- return op == TOKremove ? (RemoveExp *)this : NULL;
-}
-
-EqualExp *Expression::isEqualExp()
-{
- return (op == TOKequal || op == TOKnotequal) ? (EqualExp *)this : NULL;
-}
-
-IdentityExp *Expression::isIdentityExp()
-{
- return (op == TOKidentity || op == TOKnotidentity) ? (IdentityExp *)this : NULL;
-}
-
-CondExp *Expression::isCondExp()
-{
- return op == TOKquestion ? (CondExp *)this : NULL;
-}
-
-DefaultInitExp *Expression::isDefaultInitExp()
-{
- return op == TOKdefault ? (DefaultInitExp *)this : NULL;
-}
-
-FileInitExp *Expression::isFileInitExp()
-{
- return (op == TOKfile || op == TOKfilefullpath) ? (FileInitExp *)this : NULL;
-}
-
-LineInitExp *Expression::isLineInitExp()
-{
- return op == TOKline ? (LineInitExp *)this : NULL;
-}
-
-ModuleInitExp *Expression::isModuleInitExp()
-{
- return op == TOKmodulestring ? (ModuleInitExp *)this : NULL;
-}
-
-FuncInitExp *Expression::isFuncInitExp()
-{
- return op == TOKfuncstring ? (FuncInitExp *)this : NULL;
-}
-
-PrettyFuncInitExp *Expression::isPrettyFuncInitExp()
-{
- return op == TOKprettyfunc ? (PrettyFuncInitExp *)this : NULL;
-}
-
-ClassReferenceExp *Expression::isClassReferenceExp()
-{
- return op == TOKclassreference ? (ClassReferenceExp *)this : NULL;
-}
-
-
-/****************************************
- * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE__FULL_PATH__ to loc.
- */
-
-Expression *Expression::resolveLoc(Loc, Scope *)
-{
- return this;
-}
-
-Expressions *Expression::arraySyntaxCopy(Expressions *exps)
-{
- Expressions *a = NULL;
- if (exps)
- {
- a = new Expressions();
- a->setDim(exps->length);
- for (size_t i = 0; i < a->length; i++)
- {
- Expression *e = (*exps)[i];
- (*a)[i] = e ? e->syntaxCopy() : NULL;
- }
- }
- return a;
-}
-
-/************************************************
- * Destructors are attached to VarDeclarations.
- * Hence, if expression returns a temp that needs a destructor,
- * make sure and create a VarDeclaration for that temp.
- */
-
-Expression *Expression::addDtorHook(Scope *)
-{
- return this;
-}
-
-/******************************** IntegerExp **************************/
-
-IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type)
- : Expression(loc, TOKint64, sizeof(IntegerExp))
-{
- //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : "");
- assert(type);
- if (!type->isscalar())
- {
- //printf("%s, loc = %d\n", toChars(), loc.linnum);
- if (type->ty != Terror)
- error("integral constant must be scalar type, not %s", type->toChars());
- type = Type::terror;
- }
- this->type = type;
- setInteger(value);
-}
-
-IntegerExp::IntegerExp(dinteger_t value)
- : Expression(Loc(), TOKint64, sizeof(IntegerExp))
-{
- this->type = Type::tint32;
- this->value = (d_int32) value;
-}
-
-IntegerExp *IntegerExp::create(Loc loc, dinteger_t value, Type *type)
-{
- return new IntegerExp(loc, value, type);
-}
-
-bool IntegerExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKint64)
- {
- IntegerExp *ne = (IntegerExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- value == ne->value)
- {
- return true;
- }
- }
- return false;
-}
-
-void IntegerExp::setInteger(dinteger_t value)
-{
- this->value = value;
- normalize();
-}
-
-void IntegerExp::normalize()
-{
- /* 'Normalize' the value of the integer to be in range of the type
- */
- switch (type->toBasetype()->ty)
- {
- case Tbool: value = (value != 0); break;
- case Tint8: value = (d_int8) value; break;
- case Tchar:
- case Tuns8: value = (d_uns8) value; break;
- case Tint16: value = (d_int16) value; break;
- case Twchar:
- case Tuns16: value = (d_uns16) value; break;
- case Tint32: value = (d_int32) value; break;
- case Tdchar:
- case Tuns32: value = (d_uns32) value; break;
- case Tint64: value = (d_int64) value; break;
- case Tuns64: value = (d_uns64) value; break;
- case Tpointer:
- if (target.ptrsize == 8)
- value = (d_uns64) value;
- else if (target.ptrsize == 4)
- value = (d_uns32) value;
- else if (target.ptrsize == 2)
- value = (d_uns16) value;
- else
- assert(0);
- break;
- default:
- break;
- }
-}
-
-dinteger_t IntegerExp::toInteger()
-{
- normalize(); // necessary until we fix all the paints of 'type'
- return value;
-}
-
-real_t IntegerExp::toReal()
-{
- normalize(); // necessary until we fix all the paints of 'type'
- Type *t = type->toBasetype();
- if (t->ty == Tuns64)
- return ldouble((d_uns64)value);
- else
- return ldouble((d_int64)value);
-}
-
-real_t IntegerExp::toImaginary()
-{
- return CTFloat::zero;
-}
-
-complex_t IntegerExp::toComplex()
-{
- return (complex_t)toReal();
-}
-
-bool IntegerExp::isBool(bool result)
-{
- bool r = toInteger() != 0;
- return result ? r : !r;
-}
-
-Expression *IntegerExp::toLvalue(Scope *, Expression *e)
-{
- if (!e)
- e = this;
- else if (!loc.filename)
- loc = e->loc;
- e->error("constant %s is not an lvalue", e->toChars());
- return new ErrorExp();
-}
-
-/******************************** ErrorExp **************************/
-
-/* Use this expression for error recovery.
- * It should behave as a 'sink' to prevent further cascaded error messages.
- */
-
-ErrorExp::ErrorExp()
- : Expression(Loc(), TOKerror, sizeof(ErrorExp))
-{
- type = Type::terror;
-}
-
-Expression *ErrorExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** RealExp **************************/
-
-RealExp::RealExp(Loc loc, real_t value, Type *type)
- : Expression(loc, TOKfloat64, sizeof(RealExp))
-{
- //printf("RealExp::RealExp(%Lg)\n", value);
- this->value = value;
- this->type = type;
-}
-
-RealExp *RealExp::create(Loc loc, real_t value, Type *type)
-{
- return new RealExp(loc, value,type);
-}
-
-dinteger_t RealExp::toInteger()
-{
- return (sinteger_t) toReal();
-}
-
-uinteger_t RealExp::toUInteger()
-{
- return (uinteger_t) toReal();
-}
-
-real_t RealExp::toReal()
-{
- return type->isreal() ? value : CTFloat::zero;
-}
-
-real_t RealExp::toImaginary()
-{
- return type->isreal() ? CTFloat::zero : value;
-}
-
-complex_t RealExp::toComplex()
-{
- return complex_t(toReal(), toImaginary());
-}
-
-/********************************
- * Test to see if two reals are the same.
- * Regard NaN's as equivalent.
- * Regard +0 and -0 as different.
- */
-
-int RealEquals(real_t x1, real_t x2)
-{
- return (CTFloat::isNaN(x1) && CTFloat::isNaN(x2)) ||
- CTFloat::isIdentical(x1, x2);
-}
-
-bool RealExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKfloat64)
- {
- RealExp *ne = (RealExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- RealEquals(value, ne->value))
- {
- return true;
- }
- }
- return false;
-}
-
-bool RealExp::isBool(bool result)
-{
- return result ? (bool)value : !(bool)value;
-}
-
-/******************************** ComplexExp **************************/
-
-ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type)
- : Expression(loc, TOKcomplex80, sizeof(ComplexExp)), value(value)
-{
- this->type = type;
- //printf("ComplexExp::ComplexExp(%s)\n", toChars());
-}
-
-ComplexExp *ComplexExp::create(Loc loc, complex_t value, Type *type)
-{
- return new ComplexExp(loc, value, type);
-}
-
-dinteger_t ComplexExp::toInteger()
-{
- return (sinteger_t) toReal();
-}
-
-uinteger_t ComplexExp::toUInteger()
-{
- return (uinteger_t) toReal();
-}
-
-real_t ComplexExp::toReal()
-{
- return creall(value);
-}
-
-real_t ComplexExp::toImaginary()
-{
- return cimagl(value);
-}
-
-complex_t ComplexExp::toComplex()
-{
- return value;
-}
-
-bool ComplexExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKcomplex80)
- {
- ComplexExp *ne = (ComplexExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- RealEquals(creall(value), creall(ne->value)) &&
- RealEquals(cimagl(value), cimagl(ne->value)))
- {
- return true;
- }
- }
- return false;
-}
-
-bool ComplexExp::isBool(bool result)
-{
- if (result)
- return (bool)(value);
- else
- return !value;
-}
-
-/******************************** IdentifierExp **************************/
-
-IdentifierExp::IdentifierExp(Loc loc, Identifier *ident)
- : Expression(loc, TOKidentifier, sizeof(IdentifierExp))
-{
- this->ident = ident;
-}
-
-IdentifierExp *IdentifierExp::create(Loc loc, Identifier *ident)
-{
- return new IdentifierExp(loc, ident);
-}
-
-bool IdentifierExp::isLvalue()
-{
- return true;
-}
-
-Expression *IdentifierExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** DollarExp **************************/
-
-DollarExp::DollarExp(Loc loc)
- : IdentifierExp(loc, Id::dollar)
-{
-}
-
-/******************************** DsymbolExp **************************/
-
-DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads)
- : Expression(loc, TOKdsymbol, sizeof(DsymbolExp))
-{
- this->s = s;
- this->hasOverloads = hasOverloads;
-}
-
-/****************************************
- * Resolve a symbol `s` and wraps it in an expression object.
- * Params:
- * hasOverloads = works if the aliased symbol is a function.
- * true: it's overloaded and will be resolved later.
- * false: it's exact function symbol.
- */
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads)
-{
-Lagain:
- Expression *e;
-
- //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
- //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind());
- Dsymbol *olds = s;
- Declaration *d = s->isDeclaration();
- if (d && (d->storage_class & STCtemplateparameter))
- {
- s = s->toAlias();
- }
- else
- {
- if (!s->isFuncDeclaration()) // functions are checked after overloading
- {
- s->checkDeprecated(loc, sc);
- if (d)
- d->checkDisabled(loc, sc);
- }
-
- // Bugzilla 12023: if 's' is a tuple variable, the tuple is returned.
- s = s->toAlias();
-
- //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis());
- if (s != olds && !s->isFuncDeclaration())
- {
- s->checkDeprecated(loc, sc);
- if (d)
- d->checkDisabled(loc, sc);
- }
- }
-
- if (EnumMember *em = s->isEnumMember())
- {
- return em->getVarExp(loc, sc);
- }
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
- if (!v->type || // during variable type inference
- (!v->type->deco && v->inuse)) // during variable type semantic
- {
- if (v->inuse) // variable type depends on the variable itself
- ::error(loc, "circular reference to %s `%s`", v->kind(), v->toPrettyChars());
- else // variable type cannot be determined
- ::error(loc, "forward reference to %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- if (v->type->ty == Terror)
- return new ErrorExp();
-
- if ((v->storage_class & STCmanifest) && v->_init)
- {
- if (v->inuse)
- {
- ::error(loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
-
- e = v->expandInitializer(loc);
- v->inuse++;
- e = expressionSemantic(e, sc);
- v->inuse--;
- return e;
- }
-
- // Change the ancestor lambdas to delegate before hasThis(sc) call.
- if (v->checkNestedReference(sc, loc))
- return new ErrorExp();
-
- if (v->needThis() && hasThis(sc))
- e = new DotVarExp(loc, new ThisExp(loc), v);
- else
- e = new VarExp(loc, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
- {
- //printf("'%s' is a function literal\n", fld->toChars());
- e = new FuncExp(loc, fld);
- return expressionSemantic(e, sc);
- }
- if (FuncDeclaration *f = s->isFuncDeclaration())
- {
- f = f->toAliasFunc();
- if (!f->functionSemantic())
- return new ErrorExp();
-
- if (!hasOverloads && f->checkForwardRef(loc))
- return new ErrorExp();
-
- FuncDeclaration *fd = s->isFuncDeclaration();
- fd->type = f->type;
- return new VarExp(loc, fd, hasOverloads);
- }
- if (OverDeclaration *od = s->isOverDeclaration())
- {
- e = new VarExp(loc, od, true);
- e->type = Type::tvoid;
- return e;
- }
- if (OverloadSet *o = s->isOverloadSet())
- {
- //printf("'%s' is an overload set\n", o->toChars());
- return new OverExp(loc, o);
- }
-
- if (Import *imp = s->isImport())
- {
- if (!imp->pkg)
- {
- ::error(loc, "forward reference of import %s", imp->toChars());
- return new ErrorExp();
- }
- ScopeExp *ie = new ScopeExp(loc, imp->pkg);
- return expressionSemantic(ie, sc);
- }
- if (Package *pkg = s->isPackage())
- {
- ScopeExp *ie = new ScopeExp(loc, pkg);
- return expressionSemantic(ie, sc);
- }
- if (Module *mod = s->isModule())
- {
- ScopeExp *ie = new ScopeExp(loc, mod);
- return expressionSemantic(ie, sc);
- }
-
- if (Nspace *ns = s->isNspace())
- {
- ScopeExp *ie = new ScopeExp(loc, ns);
- return expressionSemantic(ie, sc);
- }
-
- if (Type *t = s->getType())
- {
- return expressionSemantic(new TypeExp(loc, t), sc);
- }
-
- if (TupleDeclaration *tup = s->isTupleDeclaration())
- {
- if (tup->needThis() && hasThis(sc))
- e = new DotVarExp(loc, new ThisExp(loc), tup);
- else
- e = new TupleExp(loc, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- if (TemplateInstance *ti = s->isTemplateInstance())
- {
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors)
- return new ErrorExp();
- s = ti->toAlias();
- if (!s->isTemplateInstance())
- goto Lagain;
- e = new ScopeExp(loc, ti);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- Dsymbol *p = td->toParent2();
- FuncDeclaration *fdthis = hasThis(sc);
- AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL;
- if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad &&
- (td->_scope->stc & STCstatic) == 0)
- {
- e = new DotTemplateExp(loc, new ThisExp(loc), td);
- }
- else
- e = new TemplateExp(loc, td);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- ::error(loc, "%s `%s` is not a variable", s->kind(), s->toChars());
- return new ErrorExp();
-}
-
-bool DsymbolExp::isLvalue()
-{
- return true;
-}
-
-Expression *DsymbolExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** ThisExp **************************/
-
-ThisExp::ThisExp(Loc loc)
- : Expression(loc, TOKthis, sizeof(ThisExp))
-{
- //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
- var = NULL;
-}
-
-bool ThisExp::isBool(bool result)
-{
- return result ? true : false;
-}
-
-bool ThisExp::isLvalue()
-{
- // Class `this` should be an rvalue; struct `this` should be an lvalue.
- return type->toBasetype()->ty != Tclass;
-}
-
-Expression *ThisExp::toLvalue(Scope *sc, Expression *e)
-{
- if (type->toBasetype()->ty == Tclass)
- {
- // Class `this` is an rvalue; struct `this` is an lvalue.
- return Expression::toLvalue(sc, e);
- }
- return this;
-}
-
-/******************************** SuperExp **************************/
-
-SuperExp::SuperExp(Loc loc)
- : ThisExp(loc)
-{
- op = TOKsuper;
-}
-
-/******************************** NullExp **************************/
-
-NullExp::NullExp(Loc loc, Type *type)
- : Expression(loc, TOKnull, sizeof(NullExp))
-{
- committed = 0;
- this->type = type;
-}
-
-bool NullExp::equals(RootObject *o)
-{
- if (o && o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = (Expression *)o;
- if (e->op == TOKnull &&
- type->equals(e->type))
- {
- return true;
- }
- }
- return false;
-}
-
-bool NullExp::isBool(bool result)
-{
- return result ? false : true;
-}
-
-StringExp *NullExp::toStringExp()
-{
- if (implicitConvTo(Type::tstring))
- {
- StringExp *se = new StringExp(loc, (char*)mem.xcalloc(1, 1), 0);
- se->type = Type::tstring;
- return se;
- }
- return NULL;
-}
-
-/******************************** StringExp **************************/
-
-StringExp::StringExp(Loc loc, char *string)
- : Expression(loc, TOKstring, sizeof(StringExp))
-{
- this->string = string;
- this->len = strlen(string);
- this->sz = 1;
- this->committed = 0;
- this->postfix = 0;
- this->ownedByCtfe = OWNEDcode;
-}
-
-StringExp::StringExp(Loc loc, void *string, size_t len)
- : Expression(loc, TOKstring, sizeof(StringExp))
-{
- this->string = string;
- this->len = len;
- this->sz = 1;
- this->committed = 0;
- this->postfix = 0;
- this->ownedByCtfe = OWNEDcode;
-}
-
-StringExp::StringExp(Loc loc, void *string, size_t len, utf8_t postfix)
- : Expression(loc, TOKstring, sizeof(StringExp))
-{
- this->string = string;
- this->len = len;
- this->sz = 1;
- this->committed = 0;
- this->postfix = postfix;
- this->ownedByCtfe = OWNEDcode;
-}
-
-StringExp *StringExp::create(Loc loc, char *s)
-{
- return new StringExp(loc, s);
-}
-
-StringExp *StringExp::create(Loc loc, void *string, size_t len)
-{
- return new StringExp(loc, string, len);
-}
-
-bool StringExp::equals(RootObject *o)
-{
- //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars());
- if (o && o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = (Expression *)o;
- if (e->op == TOKstring)
- {
- return compare(o) == 0;
- }
- }
- return false;
-}
-
-/**********************************
- * Return the number of code units the string would be if it were re-encoded
- * as tynto.
- * Params:
- * tynto = code unit type of the target encoding
- * Returns:
- * number of code units
- */
-
-size_t StringExp::numberOfCodeUnits(int tynto) const
-{
- int encSize;
- switch (tynto)
- {
- case 0: return len;
- case Tchar: encSize = 1; break;
- case Twchar: encSize = 2; break;
- case Tdchar: encSize = 4; break;
- default:
- assert(0);
- }
- if (sz == encSize)
- return len;
-
- size_t result = 0;
- dchar_t c;
-
- switch (sz)
- {
- case 1:
- for (size_t u = 0; u < len;)
- {
- if (const char *p = utf_decodeChar((utf8_t *)string, len, &u, &c))
- {
- error("%s", p);
- return 0;
- }
- result += utf_codeLength(encSize, c);
- }
- break;
-
- case 2:
- for (size_t u = 0; u < len;)
- {
- if (const char *p = utf_decodeWchar((utf16_t *)string, len, &u, &c))
- {
- error("%s", p);
- return 0;
- }
- result += utf_codeLength(encSize, c);
- }
- break;
-
- case 4:
- for (size_t u = 0; u < len;)
- {
- c = *((utf32_t *)((char *)string + u));
- u += 4;
- result += utf_codeLength(encSize, c);
- }
- break;
-
- default:
- assert(0);
- }
- return result;
-}
-
-/**********************************************
- * Write the contents of the string to dest.
- * Use numberOfCodeUnits() to determine size of result.
- * Params:
- * dest = destination
- * tyto = encoding type of the result
- * zero = add terminating 0
- */
-void StringExp::writeTo(void *dest, bool zero, int tyto) const
-{
- int encSize;
- switch (tyto)
- {
- case 0: encSize = sz; break;
- case Tchar: encSize = 1; break;
- case Twchar: encSize = 2; break;
- case Tdchar: encSize = 4; break;
- default:
- assert(0);
- }
- if (sz == encSize)
- {
- memcpy(dest, string, len * sz);
- if (zero)
- memset((char *)dest + len * sz, 0, sz);
- }
- else
- assert(0);
-}
-
-/**************************************************
- * If the string data is UTF-8 and can be accessed directly,
- * return a pointer to it.
- * Do not assume a terminating 0.
- * Returns:
- * pointer to string data if possible, null if not
- */
-char *StringExp::toPtr()
-{
- return (sz == 1) ? (char*)string : NULL;
-}
-
-StringExp *StringExp::toStringExp()
-{
- return this;
-}
-
-/****************************************
- * Convert string to char[].
- */
-
-StringExp *StringExp::toUTF8(Scope *sc)
-{
- if (sz != 1)
- { // Convert to UTF-8 string
- committed = 0;
- Expression *e = castTo(sc, Type::tchar->arrayOf());
- e = e->optimize(WANTvalue);
- assert(e->op == TOKstring);
- StringExp *se = (StringExp *)e;
- assert(se->sz == 1);
- return se;
- }
- return this;
-}
-
-int StringExp::compare(RootObject *obj)
-{
- //printf("StringExp::compare()\n");
- // Used to sort case statement expressions so we can do an efficient lookup
- StringExp *se2 = (StringExp *)(obj);
-
- // This is a kludge so isExpression() in template.c will return 5
- // for StringExp's.
- if (!se2)
- return 5;
-
- assert(se2->op == TOKstring);
-
- size_t len1 = len;
- size_t len2 = se2->len;
-
- //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
- if (len1 == len2)
- {
- switch (sz)
- {
- case 1:
- return memcmp((char *)string, (char *)se2->string, len1);
-
- case 2:
- {
- d_uns16 *s1 = (d_uns16 *)string;
- d_uns16 *s2 = (d_uns16 *)se2->string;
-
- for (size_t u = 0; u < len; u++)
- {
- if (s1[u] != s2[u])
- return s1[u] - s2[u];
- }
- }
- break;
-
- case 4:
- {
- d_uns32 *s1 = (d_uns32 *)string;
- d_uns32 *s2 = (d_uns32 *)se2->string;
-
- for (size_t u = 0; u < len; u++)
- {
- if (s1[u] != s2[u])
- return s1[u] - s2[u];
- }
- }
- break;
-
- default:
- assert(0);
- }
- }
- return (int)(len1 - len2);
-}
-
-bool StringExp::isBool(bool result)
-{
- return result ? true : false;
-}
-
-
-bool StringExp::isLvalue()
-{
- /* string literal is rvalue in default, but
- * conversion to reference of static array is only allowed.
- */
- return (type && type->toBasetype()->ty == Tsarray);
-}
-
-Expression *StringExp::toLvalue(Scope *sc, Expression *e)
-{
- //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
- return (type && type->toBasetype()->ty == Tsarray)
- ? this : Expression::toLvalue(sc, e);
-}
-
-Expression *StringExp::modifiableLvalue(Scope *, Expression *)
-{
- error("cannot modify string literal %s", toChars());
- return new ErrorExp();
-}
-
-unsigned StringExp::charAt(uinteger_t i) const
-{ unsigned value;
-
- switch (sz)
- {
- case 1:
- value = ((utf8_t *)string)[(size_t)i];
- break;
-
- case 2:
- value = ((unsigned short *)string)[(size_t)i];
- break;
-
- case 4:
- value = ((unsigned int *)string)[(size_t)i];
- break;
-
- default:
- assert(0);
- break;
- }
- return value;
-}
-
-/************************ ArrayLiteralExp ************************************/
-
-// [ e1, e2, e3, ... ]
-
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expressions *elements)
- : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
-{
- this->basis = NULL;
- this->type = type;
- this->elements = elements;
- this->ownedByCtfe = OWNEDcode;
-}
-
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expression *e)
- : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
-{
- this->basis = NULL;
- this->type = type;
- elements = new Expressions;
- elements->push(e);
- this->ownedByCtfe = OWNEDcode;
-}
-
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expression *basis, Expressions *elements)
- : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
-{
- this->basis = basis;
- this->type = type;
- this->elements = elements;
- this->ownedByCtfe = OWNEDcode;
-}
-
-ArrayLiteralExp *ArrayLiteralExp::create(Loc loc, Expressions *elements)
-{
- return new ArrayLiteralExp(loc, NULL, elements);
-}
-
-bool ArrayLiteralExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION &&
- ((Expression *)o)->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ae = (ArrayLiteralExp *)o;
- if (elements->length != ae->elements->length)
- return false;
- if (elements->length == 0 &&
- !type->equals(ae->type))
- {
- return false;
- }
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e1 = (*elements)[i];
- Expression *e2 = (*ae->elements)[i];
- if (!e1)
- e1 = basis;
- if (!e2)
- e2 = basis;
- if (e1 != e2 &&
- (!e1 || !e2 || !e1->equals(e2)))
- return false;
- }
- return true;
- }
- return false;
-}
-
-Expression *ArrayLiteralExp::syntaxCopy()
-{
- return new ArrayLiteralExp(loc,
- NULL,
- basis ? basis->syntaxCopy() : NULL,
- arraySyntaxCopy(elements));
-}
-
-Expression *ArrayLiteralExp::getElement(size_t i)
-{
- Expression *el = (*elements)[i];
- if (!el)
- el = basis;
- return el;
-}
-
-static void appendArrayLiteral(Expressions *elems, ArrayLiteralExp *ale)
-{
- if (!ale->elements)
- return;
- size_t d = elems->length;
- elems->append(ale->elements);
- for (size_t i = d; i < elems->length; i++)
- {
- Expression *el = (*elems)[i];
- if (!el)
- (*elems)[i] = ale->basis;
- }
-}
-
-/* Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
- * Params:
- * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
- * Otherwise, `e1` itself will be pushed into the new `Expressions`.
- * e2 = If it's not `null`, it will be pushed/appended to the new
- * `Expressions` by the same way with `e1`.
- * Returns:
- * Newly allocated `Expressions`. Note that it points to the original
- * `Expression` values in e1 and e2.
- */
-Expressions* ArrayLiteralExp::copyElements(Expression *e1, Expression *e2)
-{
- Expressions *elems = new Expressions();
-
- if (e1->op == TOKarrayliteral)
- appendArrayLiteral(elems, (ArrayLiteralExp *)e1);
- else
- elems->push(e1);
-
- if (e2)
- {
- if (e2->op == TOKarrayliteral)
- appendArrayLiteral(elems, (ArrayLiteralExp *)e2);
- else
- elems->push(e2);
- }
-
- return elems;
-}
-
-bool ArrayLiteralExp::isBool(bool result)
-{
- size_t dim = elements ? elements->length : 0;
- return result ? (dim != 0) : (dim == 0);
-}
-
-StringExp *ArrayLiteralExp::toStringExp()
-{
- TY telem = type->nextOf()->toBasetype()->ty;
-
- if (telem == Tchar || telem == Twchar || telem == Tdchar ||
- (telem == Tvoid && (!elements || elements->length == 0)))
- {
- unsigned char sz = 1;
- if (telem == Twchar) sz = 2;
- else if (telem == Tdchar) sz = 4;
-
- OutBuffer buf;
- if (elements)
- {
- for (size_t i = 0; i < elements->length; ++i)
- {
- Expression *ch = getElement(i);
- if (ch->op != TOKint64)
- return NULL;
- if (sz == 1)
- buf.writeByte((unsigned)ch->toInteger());
- else if (sz == 2)
- buf.writeword((unsigned)ch->toInteger());
- else
- buf.write4((unsigned)ch->toInteger());
- }
- }
- char prefix;
- if (sz == 1) { prefix = 'c'; buf.writeByte(0); }
- else if (sz == 2) { prefix = 'w'; buf.writeword(0); }
- else { prefix = 'd'; buf.write4(0); }
-
- const size_t len = buf.length() / sz - 1;
- StringExp *se = new StringExp(loc, buf.extractData(), len, prefix);
- se->sz = sz;
- se->type = type;
- return se;
- }
- return NULL;
-}
-
-/************************ AssocArrayLiteralExp ************************************/
-
-// [ key0 : value0, key1 : value1, ... ]
-
-AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc,
- Expressions *keys, Expressions *values)
- : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp))
-{
- assert(keys->length == values->length);
- this->keys = keys;
- this->values = values;
- this->ownedByCtfe = OWNEDcode;
-}
-
-bool AssocArrayLiteralExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION &&
- ((Expression *)o)->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)o;
- if (keys->length != ae->keys->length)
- return false;
- size_t count = 0;
- for (size_t i = 0; i < keys->length; i++)
- {
- for (size_t j = 0; j < ae->keys->length; j++)
- {
- if ((*keys)[i]->equals((*ae->keys)[j]))
- {
- if (!(*values)[i]->equals((*ae->values)[j]))
- return false;
- ++count;
- }
- }
- }
- return count == keys->length;
- }
- return false;
-}
-
-Expression *AssocArrayLiteralExp::syntaxCopy()
-{
- return new AssocArrayLiteralExp(loc,
- arraySyntaxCopy(keys), arraySyntaxCopy(values));
-}
-
-bool AssocArrayLiteralExp::isBool(bool result)
-{
- size_t dim = keys->length;
- return result ? (dim != 0) : (dim == 0);
-}
-
-/************************ StructLiteralExp ************************************/
-
-// sd( e1, e2, e3, ... )
-
-StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype)
- : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp))
-{
- this->sd = sd;
- if (!elements)
- elements = new Expressions();
- this->elements = elements;
- this->stype = stype;
- this->useStaticInit = false;
- this->sym = NULL;
- this->ownedByCtfe = OWNEDcode;
- this->origin = this;
- this->stageflags = 0;
- this->inlinecopy = NULL;
- //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
-}
-
-StructLiteralExp *StructLiteralExp::create(Loc loc, StructDeclaration *sd, void *elements, Type *stype)
-{
- return new StructLiteralExp(loc, sd, (Expressions *)elements, stype);
-}
-
-bool StructLiteralExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION &&
- ((Expression *)o)->op == TOKstructliteral)
- {
- StructLiteralExp *se = (StructLiteralExp *)o;
- if (!type->equals(se->type))
- return false;
- if (elements->length != se->elements->length)
- return false;
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e1 = (*elements)[i];
- Expression *e2 = (*se->elements)[i];
- if (e1 != e2 &&
- (!e1 || !e2 || !e1->equals(e2)))
- return false;
- }
- return true;
- }
- return false;
-}
-
-Expression *StructLiteralExp::syntaxCopy()
-{
- StructLiteralExp *exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
- exp->origin = this;
- return exp;
-}
-
-Expression *StructLiteralExp::addDtorHook(Scope *sc)
-{
- /* If struct requires a destructor, rewrite as:
- * (S tmp = S()),tmp
- * so that the destructor can be hung on tmp.
- */
- if (sd->dtor && sc->func)
- {
- /* Make an identifier for the temporary of the form:
- * __sl%s%d, where %s is the struct name
- */
- const size_t len = 10;
- char buf[len + 1];
- buf[len] = 0;
- strcpy(buf, "__sl");
- strncat(buf, sd->ident->toChars(), len - 4 - 1);
- assert(buf[len] == 0);
-
- VarDeclaration *tmp = copyToTemp(0, buf, this);
- Expression *ae = new DeclarationExp(loc, tmp);
- Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp));
- e = expressionSemantic(e, sc);
- return e;
- }
- return this;
-}
-
-/**************************************
- * Gets expression at offset of type.
- * Returns NULL if not found.
- */
-
-Expression *StructLiteralExp::getField(Type *type, unsigned offset)
-{
- //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
- // /*toChars()*/"", type->toChars(), offset);
- Expression *e = NULL;
- int i = getFieldIndex(type, offset);
-
- if (i != -1)
- {
- //printf("\ti = %d\n", i);
- if (i == (int)sd->fields.length - 1 && sd->isNested())
- return NULL;
-
- assert(i < (int)elements->length);
- e = (*elements)[i];
- if (e)
- {
- //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars());
-
- /* If type is a static array, and e is an initializer for that array,
- * then the field initializer should be an array literal of e.
- */
- if (e->type->castMod(0) != type->castMod(0) && type->ty == Tsarray)
- { TypeSArray *tsa = (TypeSArray *)type;
- size_t length = (size_t)tsa->dim->toInteger();
- Expressions *z = new Expressions;
- z->setDim(length);
- for (size_t q = 0; q < length; ++q)
- (*z)[q] = e->copy();
- e = new ArrayLiteralExp(loc, type, z);
- }
- else
- {
- e = e->copy();
- e->type = type;
- }
- if (useStaticInit && e->op == TOKstructliteral &&
- e->type->needsNested())
- {
- StructLiteralExp *se = (StructLiteralExp *)e;
- se->useStaticInit = true;
- }
- }
- }
- return e;
-}
-
-/************************************
- * Get index of field.
- * Returns -1 if not found.
- */
-
-int StructLiteralExp::getFieldIndex(Type *type, unsigned offset)
-{
- /* Find which field offset is by looking at the field offsets
- */
- if (elements->length)
- {
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
-
- if (offset == v->offset &&
- type->size() == v->type->size())
- {
- /* context field might not be filled. */
- if (i == sd->fields.length - 1 && sd->isNested())
- return (int)i;
- Expression *e = (*elements)[i];
- if (e)
- {
- return (int)i;
- }
- break;
- }
- }
- }
- return -1;
-}
-
-/************************ TypeDotIdExp ************************************/
-
-/* Things like:
- * int.size
- * foo.size
- * (foo).size
- * cast(foo).size
- */
-
-DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident)
-{
- return new DotIdExp(loc, new TypeExp(loc, type), ident);
-}
-
-
-/************************************************************/
-
-// Mainly just a placeholder
-
-TypeExp::TypeExp(Loc loc, Type *type)
- : Expression(loc, TOKtype, sizeof(TypeExp))
-{
- //printf("TypeExp::TypeExp(%s)\n", type->toChars());
- this->type = type;
-}
-
-Expression *TypeExp::syntaxCopy()
-{
- return new TypeExp(loc, type->syntaxCopy());
-}
-
-bool TypeExp::checkType()
-{
- error("type %s is not an expression", toChars());
- return true;
-}
-
-bool TypeExp::checkValue()
-{
- error("type %s has no value", toChars());
- return true;
-}
-
-/************************************************************/
-
-/***********************************************************
- * Mainly just a placeholder of
- * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
- *
- * A template instance that requires IFTI:
- * foo!tiargs(fargs) // foo!tiargs
- * is left until CallExp::semantic() or resolveProperties()
- */
-ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *sds)
- : Expression(loc, TOKscope, sizeof(ScopeExp))
-{
- //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds->toChars());
- //static int count; if (++count == 38) *(char*)0=0;
- this->sds = sds;
- assert(!sds->isTemplateDeclaration()); // instead, you should use TemplateExp
-}
-
-Expression *ScopeExp::syntaxCopy()
-{
- return new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL));
-}
-
-bool ScopeExp::checkType()
-{
- if (sds->isPackage())
- {
- error("%s %s has no type", sds->kind(), sds->toChars());
- return true;
- }
- if (TemplateInstance *ti = sds->isTemplateInstance())
- {
- //assert(ti->needsTypeInference(sc));
- if (ti->tempdecl &&
- ti->semantictiargsdone &&
- ti->semanticRun == PASSinit)
- {
- error("partial %s %s has no type", sds->kind(), toChars());
- return true;
- }
- }
- return false;
-}
-
-bool ScopeExp::checkValue()
-{
- error("%s %s has no value", sds->kind(), sds->toChars());
- return true;
-}
-
-/********************** TemplateExp **************************************/
-
-// Mainly just a placeholder
-
-TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd)
- : Expression(loc, TOKtemplate, sizeof(TemplateExp))
-{
- //printf("TemplateExp(): %s\n", td->toChars());
- this->td = td;
- this->fd = fd;
-}
-
-bool TemplateExp::checkType()
-{
- error("%s %s has no type", td->kind(), toChars());
- return true;
-}
-
-bool TemplateExp::checkValue()
-{
- error("%s %s has no value", td->kind(), toChars());
- return true;
-}
-
-bool TemplateExp::isLvalue()
-{
- return fd != NULL;
-}
-
-Expression *TemplateExp::toLvalue(Scope *sc, Expression *e)
-{
- if (!fd)
- return Expression::toLvalue(sc, e);
-
- assert(sc);
- return resolve(loc, sc, fd, true);
-}
-
-/********************** NewExp **************************************/
-
-/* thisexp.new(newargs) newtype(arguments) */
-
-NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
- Type *newtype, Expressions *arguments)
- : Expression(loc, TOKnew, sizeof(NewExp))
-{
- this->thisexp = thisexp;
- this->newargs = newargs;
- this->newtype = newtype;
- this->arguments = arguments;
- argprefix = NULL;
- member = NULL;
- allocator = NULL;
- onstack = 0;
-}
-
-NewExp *NewExp::create(Loc loc, Expression *thisexp, Expressions *newargs,
- Type *newtype, Expressions *arguments)
-{
- return new NewExp(loc, thisexp, newargs, newtype, arguments);
-}
-
-Expression *NewExp::syntaxCopy()
-{
- return new NewExp(loc,
- thisexp ? thisexp->syntaxCopy() : NULL,
- arraySyntaxCopy(newargs),
- newtype->syntaxCopy(), arraySyntaxCopy(arguments));
-}
-
-/********************** NewAnonClassExp **************************************/
-
-NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp,
- Expressions *newargs, ClassDeclaration *cd, Expressions *arguments)
- : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp))
-{
- this->thisexp = thisexp;
- this->newargs = newargs;
- this->cd = cd;
- this->arguments = arguments;
-}
-
-Expression *NewAnonClassExp::syntaxCopy()
-{
- return new NewAnonClassExp(loc,
- thisexp ? thisexp->syntaxCopy() : NULL,
- arraySyntaxCopy(newargs),
- (ClassDeclaration *)cd->syntaxCopy(NULL),
- arraySyntaxCopy(arguments));
-}
-
-/********************** SymbolExp **************************************/
-
-SymbolExp::SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads)
- : Expression(loc, op, size)
-{
- assert(var);
- this->var = var;
- this->hasOverloads = hasOverloads;
-}
-
-/********************** SymOffExp **************************************/
-
-SymOffExp::SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads)
- : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var,
- var->isVarDeclaration() ? false : hasOverloads)
-{
- if (VarDeclaration *v = var->isVarDeclaration())
- {
- // FIXME: This error report will never be handled anyone.
- // It should be done before the SymOffExp construction.
- if (v->needThis())
- ::error(loc, "need `this` for address of %s", v->toChars());
- }
- this->offset = offset;
-}
-
-bool SymOffExp::isBool(bool result)
-{
- return result ? true : false;
-}
-
-/******************************** VarExp **************************/
-
-VarExp::VarExp(Loc loc, Declaration *var, bool hasOverloads)
- : SymbolExp(loc, TOKvar, sizeof(VarExp), var,
- var->isVarDeclaration() ? false : hasOverloads)
-{
- //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars());
- //if (strcmp(var->ident->toChars(), "func") == 0) halt();
- this->type = var->type;
-}
-
-VarExp *VarExp::create(Loc loc, Declaration *var, bool hasOverloads)
-{
- return new VarExp(loc, var, hasOverloads);
-}
-
-bool VarExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKvar)
- {
- VarExp *ne = (VarExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- var == ne->var)
- {
- return true;
- }
- }
- return false;
-}
-
-bool VarExp::isLvalue()
-{
- if (var->storage_class & (STClazy | STCrvalue | STCmanifest))
- return false;
- return true;
-}
-
-Expression *VarExp::toLvalue(Scope *, Expression *)
-{
- if (var->storage_class & STCmanifest)
- {
- error("manifest constant `%s` is not lvalue", var->toChars());
- return new ErrorExp();
- }
- if (var->storage_class & STClazy)
- {
- error("lazy variables cannot be lvalues");
- return new ErrorExp();
- }
- if (var->ident == Id::ctfe)
- {
- error("compiler-generated variable __ctfe is not an lvalue");
- return new ErrorExp();
- }
- if (var->ident == Id::dollar) // Bugzilla 13574
- {
- error("`$` is not an lvalue");
- return new ErrorExp();
- }
- return this;
-}
-
-int VarExp::checkModifiable(Scope *sc, int flag)
-{
- //printf("VarExp::checkModifiable %s", toChars());
- assert(type);
- return var->checkModify(loc, sc, type, NULL, flag);
-}
-
-Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("VarExp::modifiableLvalue('%s')\n", var->toChars());
- if (var->storage_class & STCmanifest)
- {
- error("cannot modify manifest constant `%s`", toChars());
- return new ErrorExp();
- }
- // See if this expression is a modifiable lvalue (i.e. not const)
- return Expression::modifiableLvalue(sc, e);
-}
-
-
-/******************************** OverExp **************************/
-
-OverExp::OverExp(Loc loc, OverloadSet *s)
- : Expression(loc, TOKoverloadset, sizeof(OverExp))
-{
- //printf("OverExp(this = %p, '%s')\n", this, var->toChars());
- vars = s;
- type = Type::tvoid;
-}
-
-bool OverExp::isLvalue()
-{
- return true;
-}
-
-Expression *OverExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** TupleExp **************************/
-
-TupleExp::TupleExp(Loc loc, Expression *e0, Expressions *exps)
- : Expression(loc, TOKtuple, sizeof(TupleExp))
-{
- //printf("TupleExp(this = %p)\n", this);
- this->e0 = e0;
- this->exps = exps;
-}
-
-TupleExp::TupleExp(Loc loc, Expressions *exps)
- : Expression(loc, TOKtuple, sizeof(TupleExp))
-{
- //printf("TupleExp(this = %p)\n", this);
- this->e0 = NULL;
- this->exps = exps;
-}
-
-TupleExp::TupleExp(Loc loc, TupleDeclaration *tup)
- : Expression(loc, TOKtuple, sizeof(TupleExp))
-{
- this->e0 = NULL;
- this->exps = new Expressions();
-
- this->exps->reserve(tup->objects->length);
- for (size_t i = 0; i < tup->objects->length; i++)
- { RootObject *o = (*tup->objects)[i];
- if (Dsymbol *s = getDsymbol(o))
- {
- /* If tuple element represents a symbol, translate to DsymbolExp
- * to supply implicit 'this' if needed later.
- */
- Expression *e = new DsymbolExp(loc, s);
- this->exps->push(e);
- }
- else if (o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = ((Expression *)o)->copy();
- e->loc = loc; // Bugzilla 15669
- this->exps->push(e);
- }
- else if (o->dyncast() == DYNCAST_TYPE)
- {
- Type *t = (Type *)o;
- Expression *e = new TypeExp(loc, t);
- this->exps->push(e);
- }
- else
- {
- error("%s is not an expression", o->toChars());
- }
- }
-}
-
-bool TupleExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)o;
- if (exps->length != te->exps->length)
- return false;
- if ((e0 && !e0->equals(te->e0)) || (!e0 && te->e0))
- return false;
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e1 = (*exps)[i];
- Expression *e2 = (*te->exps)[i];
- if (!e1->equals(e2))
- return false;
- }
- return true;
- }
- return false;
-}
-
-Expression *TupleExp::syntaxCopy()
-{
- return new TupleExp(loc, e0 ? e0->syntaxCopy() : NULL, arraySyntaxCopy(exps));
-}
-
-TupleExp *TupleExp::toTupleExp()
-{
- return this;
-}
-
-/******************************** FuncExp *********************************/
-
-FuncExp::FuncExp(Loc loc, Dsymbol *s)
- : Expression(loc, TOKfunction, sizeof(FuncExp))
-{
- this->td = s->isTemplateDeclaration();
- this->fd = s->isFuncLiteralDeclaration();
- if (td)
- {
- assert(td->literal);
- assert(td->members && td->members->length == 1);
- fd = (*td->members)[0]->isFuncLiteralDeclaration();
- }
- tok = fd->tok; // save original kind of function/delegate/(infer)
- assert(fd->fbody);
-}
-
-bool FuncExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o->dyncast() != DYNCAST_EXPRESSION)
- return false;
- if (((Expression *)o)->op == TOKfunction)
- {
- FuncExp *fe = (FuncExp *)o;
- return fd == fe->fd;
- }
- return false;
-}
-
-void FuncExp::genIdent(Scope *sc)
-{
- if (fd->ident == Id::empty)
- {
- const char *s;
- if (fd->fes) s = "__foreachbody";
- else if (fd->tok == TOKreserved) s = "__lambda";
- else if (fd->tok == TOKdelegate) s = "__dgliteral";
- else s = "__funcliteral";
-
- DsymbolTable *symtab;
- if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
- {
- if (func->localsymtab == NULL)
- {
- // Inside template constraint, symtab is not set yet.
- // Initialize it lazily.
- func->localsymtab = new DsymbolTable();
- }
- symtab = func->localsymtab;
- }
- else
- {
- ScopeDsymbol *sds = sc->parent->isScopeDsymbol();
- if (!sds->symtab)
- {
- // Inside template constraint, symtab may not be set yet.
- // Initialize it lazily.
- assert(sds->isTemplateInstance());
- sds->symtab = new DsymbolTable();
- }
- symtab = sds->symtab;
- }
- assert(symtab);
- int num = (int)dmd_aaLen(symtab->tab) + 1;
- Identifier *id = Identifier::generateId(s, num);
- fd->ident = id;
- if (td) td->ident = id;
- symtab->insert(td ? (Dsymbol *)td : (Dsymbol *)fd);
- }
-}
-
-Expression *FuncExp::syntaxCopy()
-{
- if (td)
- return new FuncExp(loc, td->syntaxCopy(NULL));
- else if (fd->semanticRun == PASSinit)
- return new FuncExp(loc, fd->syntaxCopy(NULL));
- else // Bugzilla 13481: Prevent multiple semantic analysis of lambda body.
- return new FuncExp(loc, fd);
-}
-
-MATCH FuncExp::matchType(Type *to, Scope *sc, FuncExp **presult, int flag)
-{
- //printf("FuncExp::matchType('%s'), to=%s\n", type ? type->toChars() : "null", to->toChars());
- if (presult)
- *presult = NULL;
-
- TypeFunction *tof = NULL;
- if (to->ty == Tdelegate)
- {
- if (tok == TOKfunction)
- {
- if (!flag)
- error("cannot match function literal to delegate type `%s`", to->toChars());
- return MATCHnomatch;
- }
- tof = (TypeFunction *)to->nextOf();
- }
- else if (to->ty == Tpointer && to->nextOf()->ty == Tfunction)
- {
- if (tok == TOKdelegate)
- {
- if (!flag)
- error("cannot match delegate literal to function pointer type `%s`", to->toChars());
- return MATCHnomatch;
- }
- tof = (TypeFunction *)to->nextOf();
- }
-
- if (td)
- {
- if (!tof)
- {
- L1:
- if (!flag)
- error("cannot infer parameter types from %s", to->toChars());
- return MATCHnomatch;
- }
-
- // Parameter types inference from 'tof'
- assert(td->_scope);
- TypeFunction *tf = (TypeFunction *)fd->type;
- //printf("\ttof = %s\n", tof->toChars());
- //printf("\ttf = %s\n", tf->toChars());
- size_t dim = tf->parameterList.length();
-
- if (tof->parameterList.length() != dim ||
- tof->parameterList.varargs != tf->parameterList.varargs)
- goto L1;
-
- Objects *tiargs = new Objects();
- tiargs->reserve(td->parameters->length);
-
- for (size_t i = 0; i < td->parameters->length; i++)
- {
- TemplateParameter *tp = (*td->parameters)[i];
- size_t u = 0;
- for (; u < dim; u++)
- {
- Parameter *p = tf->parameterList[u];
- if (p->type->ty == Tident &&
- ((TypeIdentifier *)p->type)->ident == tp->ident)
- {
- break;
- }
- }
- assert(u < dim);
- Parameter *pto = tof->parameterList[u];
- Type *t = pto->type;
- if (t->ty == Terror)
- goto L1;
- tiargs->push(t);
- }
-
- // Set target of return type inference
- if (!tf->next && tof->next)
- fd->treq = to;
-
- TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
- Expression *ex = new ScopeExp(loc, ti);
- ex = expressionSemantic(ex, td->_scope);
-
- // Reset inference target for the later re-semantic
- fd->treq = NULL;
-
- if (ex->op == TOKerror)
- return MATCHnomatch;
- if (ex->op != TOKfunction)
- goto L1;
- return ((FuncExp *)ex)->matchType(to, sc, presult, flag);
- }
-
- if (!tof || !tof->next)
- return MATCHnomatch;
-
- assert(type && type != Type::tvoid);
- TypeFunction *tfx = (TypeFunction *)fd->type;
- bool convertMatch = (type->ty != to->ty);
-
- if (fd->inferRetType && tfx->next->implicitConvTo(tof->next) == MATCHconvert)
- {
- /* If return type is inferred and covariant return,
- * tweak return statements to required return type.
- *
- * interface I {}
- * class C : Object, I{}
- *
- * I delegate() dg = delegate() { return new class C(); }
- */
- convertMatch = true;
-
- TypeFunction *tfy = new TypeFunction(tfx->parameterList, tof->next, tfx->linkage, STCundefined);
- tfy->mod = tfx->mod;
- tfy->isnothrow = tfx->isnothrow;
- tfy->isnogc = tfx->isnogc;
- tfy->purity = tfx->purity;
- tfy->isproperty = tfx->isproperty;
- tfy->isref = tfx->isref;
- tfy->iswild = tfx->iswild;
- tfy->deco = tfy->merge()->deco;
-
- tfx = tfy;
- }
-
- Type *tx;
- if (tok == TOKdelegate ||
- (tok == TOKreserved && (type->ty == Tdelegate ||
- (type->ty == Tpointer && to->ty == Tdelegate))))
- {
- // Allow conversion from implicit function pointer to delegate
- tx = new TypeDelegate(tfx);
- tx->deco = tx->merge()->deco;
- }
- else
- {
- assert(tok == TOKfunction ||
- (tok == TOKreserved && type->ty == Tpointer));
- tx = tfx->pointerTo();
- }
- //printf("\ttx = %s, to = %s\n", tx->toChars(), to->toChars());
-
- MATCH m = tx->implicitConvTo(to);
- if (m > MATCHnomatch)
- {
- // MATCHexact: exact type match
- // MATCHconst: covairiant type match (eg. attributes difference)
- // MATCHconvert: context conversion
- m = convertMatch ? MATCHconvert : tx->equals(to) ? MATCHexact : MATCHconst;
-
- if (presult)
- {
- (*presult) = (FuncExp *)copy();
- (*presult)->type = to;
-
- // Bugzilla 12508: Tweak function body for covariant returns.
- (*presult)->fd->modifyReturns(sc, tof->next);
- }
- }
- else if (!flag)
- {
- const char *ts[2];
- toAutoQualChars(ts, tx, to);
- error("cannot implicitly convert expression (%s) of type %s to %s",
- toChars(), ts[0], ts[1]);
- }
- return m;
-}
-
-const char *FuncExp::toChars()
-{
- return fd->toChars();
-}
-
-bool FuncExp::checkType()
-{
- if (td)
- {
- error("template lambda has no type");
- return true;
- }
- return false;
-}
-
-bool FuncExp::checkValue()
-{
- if (td)
- {
- error("template lambda has no value");
- return true;
- }
- return false;
-}
-
-/******************************** DeclarationExp **************************/
-
-DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration)
- : Expression(loc, TOKdeclaration, sizeof(DeclarationExp))
-{
- this->declaration = declaration;
-}
-
-Expression *DeclarationExp::syntaxCopy()
-{
- return new DeclarationExp(loc, declaration->syntaxCopy(NULL));
-}
-
-bool DeclarationExp::hasCode()
-{
- if (VarDeclaration *vd = declaration->isVarDeclaration())
- {
- return !(vd->storage_class & (STCmanifest | STCstatic));
- }
- return false;
-}
-
-/************************ TypeidExp ************************************/
-
-/*
- * typeid(int)
- */
-
-TypeidExp::TypeidExp(Loc loc, RootObject *o)
- : Expression(loc, TOKtypeid, sizeof(TypeidExp))
-{
- this->obj = o;
-}
-
-Expression *TypeidExp::syntaxCopy()
-{
- return new TypeidExp(loc, objectSyntaxCopy(obj));
-}
-
-/************************ TraitsExp ************************************/
-/*
- * __traits(identifier, args...)
- */
-
-TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args)
- : Expression(loc, TOKtraits, sizeof(TraitsExp))
-{
- this->ident = ident;
- this->args = args;
-}
-
-Expression *TraitsExp::syntaxCopy()
-{
- return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args));
-}
-
-/************************************************************/
-
-HaltExp::HaltExp(Loc loc)
- : Expression(loc, TOKhalt, sizeof(HaltExp))
-{
-}
-
-/************************************************************/
-
-IsExp::IsExp(Loc loc, Type *targ, Identifier *id, TOK tok,
- Type *tspec, TOK tok2, TemplateParameters *parameters)
- : Expression(loc, TOKis, sizeof(IsExp))
-{
- this->targ = targ;
- this->id = id;
- this->tok = tok;
- this->tspec = tspec;
- this->tok2 = tok2;
- this->parameters = parameters;
-}
-
-Expression *IsExp::syntaxCopy()
-{
- // This section is identical to that in TemplateDeclaration::syntaxCopy()
- TemplateParameters *p = NULL;
- if (parameters)
- {
- p = new TemplateParameters();
- p->setDim(parameters->length);
- for (size_t i = 0; i < p->length; i++)
- (*p)[i] = (*parameters)[i]->syntaxCopy();
- }
- return new IsExp(loc,
- targ->syntaxCopy(),
- id,
- tok,
- tspec ? tspec->syntaxCopy() : NULL,
- tok2,
- p);
-}
-
-void unSpeculative(Scope *sc, RootObject *o);
-
-/************************************************************/
-
-UnaExp::UnaExp(Loc loc, TOK op, int size, Expression *e1)
- : Expression(loc, op, size)
-{
- this->e1 = e1;
- this->att1 = NULL;
-}
-
-Expression *UnaExp::syntaxCopy()
-{
- UnaExp *e = (UnaExp *)copy();
- e->type = NULL;
- e->e1 = e->e1->syntaxCopy();
- return e;
-}
-
-/********************************
- * The type for a unary expression is incompatible.
- * Print error message.
- * Returns:
- * ErrorExp
- */
-Expression *UnaExp::incompatibleTypes()
-{
- if (e1->type->toBasetype() == Type::terror)
- return e1;
-
- if (e1->op == TOKtype)
- {
- error("incompatible type for (%s(%s)): cannot use `%s` with types",
- Token::toChars(op), e1->toChars(), Token::toChars(op));
- }
- else
- {
- error("incompatible type for (%s(%s)): `%s`",
- Token::toChars(op), e1->toChars(), e1->type->toChars());
- }
- return new ErrorExp();
-}
-
-Expression *UnaExp::resolveLoc(Loc loc, Scope *sc)
-{
- e1 = e1->resolveLoc(loc, sc);
- return this;
-}
-
-/************************************************************/
-
-BinExp::BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
- : Expression(loc, op, size)
-{
- this->e1 = e1;
- this->e2 = e2;
-
- this->att1 = NULL;
- this->att2 = NULL;
-}
-
-Expression *BinExp::syntaxCopy()
-{
- BinExp *e = (BinExp *)copy();
- e->type = NULL;
- e->e1 = e->e1->syntaxCopy();
- e->e2 = e->e2->syntaxCopy();
- return e;
-}
-
-Expression *BinExp::checkOpAssignTypes(Scope *sc)
-{
- // At that point t1 and t2 are the merged types. type is the original type of the lhs.
- Type *t1 = e1->type;
- Type *t2 = e2->type;
-
- // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
- // See issue 3841.
- // Should we also prevent double to float (type->isfloating() && type->size() < t2 ->size()) ?
- if (op == TOKaddass || op == TOKminass ||
- op == TOKmulass || op == TOKdivass || op == TOKmodass ||
- op == TOKpowass)
- {
- if ((type->isintegral() && t2->isfloating()))
- {
- warning("%s %s %s is performing truncating conversion",
- type->toChars(), Token::toChars(op), t2->toChars());
- }
- }
-
- // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
- if (op == TOKmulass || op == TOKdivass || op == TOKmodass)
- {
- // Any multiplication by an imaginary or complex number yields a complex result.
- // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
- const char *opstr = Token::toChars(op);
- if (t1->isreal() && t2->iscomplex())
- {
- error("%s %s %s is undefined. Did you mean %s %s %s.re ?",
- t1->toChars(), opstr, t2->toChars(),
- t1->toChars(), opstr, t2->toChars());
- return new ErrorExp();
- }
- else if (t1->isimaginary() && t2->iscomplex())
- {
- error("%s %s %s is undefined. Did you mean %s %s %s.im ?",
- t1->toChars(), opstr, t2->toChars(),
- t1->toChars(), opstr, t2->toChars());
- return new ErrorExp();
- }
- else if ((t1->isreal() || t1->isimaginary()) &&
- t2->isimaginary())
- {
- error("%s %s %s is an undefined operation", t1->toChars(), opstr, t2->toChars());
- return new ErrorExp();
- }
- }
-
- // generate an error if this is a nonsensical += or -=, eg real += imaginary
- if (op == TOKaddass || op == TOKminass)
- {
- // Addition or subtraction of a real and an imaginary is a complex result.
- // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
- if ((t1->isreal() && (t2->isimaginary() || t2->iscomplex())) ||
- (t1->isimaginary() && (t2->isreal() || t2->iscomplex())))
- {
- error("%s %s %s is undefined (result is complex)",
- t1->toChars(), Token::toChars(op), t2->toChars());
- return new ErrorExp();
- }
- if (type->isreal() || type->isimaginary())
- {
- assert(global.errors || t2->isfloating());
- e2 = e2->castTo(sc, t1);
- }
- }
-
- if (op == TOKmulass)
- {
- if (t2->isfloating())
- {
- if (t1->isreal())
- {
- if (t2->isimaginary() || t2->iscomplex())
- {
- e2 = e2->castTo(sc, t1);
- }
- }
- else if (t1->isimaginary())
- {
- if (t2->isimaginary() || t2->iscomplex())
- {
- switch (t1->ty)
- {
- case Timaginary32: t2 = Type::tfloat32; break;
- case Timaginary64: t2 = Type::tfloat64; break;
- case Timaginary80: t2 = Type::tfloat80; break;
- default:
- assert(0);
- }
- e2 = e2->castTo(sc, t2);
- }
- }
- }
- }
- else if (op == TOKdivass)
- {
- if (t2->isimaginary())
- {
- if (t1->isreal())
- {
- // x/iv = i(-x/v)
- // Therefore, the result is 0
- e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat::zero, t1));
- e2->type = t1;
- Expression *e = new AssignExp(loc, e1, e2);
- e->type = t1;
- return e;
- }
- else if (t1->isimaginary())
- {
- Type *t3;
- switch (t1->ty)
- {
- case Timaginary32: t3 = Type::tfloat32; break;
- case Timaginary64: t3 = Type::tfloat64; break;
- case Timaginary80: t3 = Type::tfloat80; break;
- default:
- assert(0);
- }
- e2 = e2->castTo(sc, t3);
- Expression *e = new AssignExp(loc, e1, e2);
- e->type = t1;
- return e;
- }
- }
- }
- else if (op == TOKmodass)
- {
- if (t2->iscomplex())
- {
- error("cannot perform modulo complex arithmetic");
- return new ErrorExp();
- }
- }
- return this;
-}
-
-/********************************
- * The types for a binary expression are incompatible.
- * Print error message.
- * Returns:
- * ErrorExp
- */
-Expression *BinExp::incompatibleTypes()
-{
- if (e1->type->toBasetype() == Type::terror)
- return e1;
- if (e2->type->toBasetype() == Type::terror)
- return e2;
-
- // CondExp uses 'a ? b : c' but we're comparing 'b : c'
- TOK thisOp = (op == TOKquestion) ? TOKcolon : op;
- if (e1->op == TOKtype || e2->op == TOKtype)
- {
- error("incompatible types for ((%s) %s (%s)): cannot use `%s` with types",
- e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op));
- }
- else if (e1->type->equals(e2->type))
- {
- error("incompatible types for ((%s) %s (%s)): both operands are of type `%s`",
- e1->toChars(), Token::toChars(thisOp), e2->toChars(), e1->type->toChars());
- }
- else
- {
- const char *ts[2];
- toAutoQualChars(ts, e1->type, e2->type);
- error("incompatible types for ((%s) %s (%s)): `%s` and `%s`",
- e1->toChars(), Token::toChars(thisOp), e2->toChars(), ts[0], ts[1]);
- }
- return new ErrorExp();
-}
-
-bool BinExp::checkIntegralBin()
-{
- bool r1 = e1->checkIntegral();
- bool r2 = e2->checkIntegral();
- return (r1 || r2);
-}
-
-bool BinExp::checkArithmeticBin()
-{
- bool r1 = e1->checkArithmetic();
- bool r2 = e2->checkArithmetic();
- return (r1 || r2);
-}
-
-/********************** BinAssignExp **************************************/
-
-BinAssignExp::BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
- : BinExp(loc, op, size, e1, e2)
-{
-}
-
-bool BinAssignExp::isLvalue()
-{
- return true;
-}
-
-Expression *BinAssignExp::toLvalue(Scope *, Expression *)
-{
- // Lvalue-ness will be handled in glue layer.
- return this;
-}
-
-Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *)
-{
- // should check e1->checkModifiable() ?
- return toLvalue(sc, this);
-}
-
-/************************************************************/
-
-CompileExp::CompileExp(Loc loc, Expressions *exps)
- : Expression(loc, TOKmixin, sizeof(CompileExp))
-{
- this->exps = exps;
-}
-
-Expression *CompileExp::syntaxCopy()
-{
- return new CompileExp(loc, arraySyntaxCopy(exps));
-}
-
-bool CompileExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION && ((Expression *)o)->op == TOKmixin)
- {
- CompileExp *ce = (CompileExp *)o;
- if (exps->length != ce->exps->length)
- return false;
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e1 = (*exps)[i];
- Expression *e2 = (*ce->exps)[i];
- if (e1 != e2 && (!e1 || !e2 || !e1->equals(e2)))
- return false;
- }
- return true;
- }
- return false;
-}
-
-/************************************************************/
-
-ImportExp::ImportExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKimport, sizeof(ImportExp), e)
-{
-}
-
-/************************************************************/
-
-AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg)
- : UnaExp(loc, TOKassert, sizeof(AssertExp), e)
-{
- this->msg = msg;
-}
-
-Expression *AssertExp::syntaxCopy()
-{
- return new AssertExp(loc, e1->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
-}
-
-/************************************************************/
-
-DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident)
- : UnaExp(loc, TOKdotid, sizeof(DotIdExp), e)
-{
- this->ident = ident;
- this->wantsym = false;
- this->noderef = false;
-}
-
-DotIdExp *DotIdExp::create(Loc loc, Expression *e, Identifier *ident)
-{
- return new DotIdExp(loc, e, ident);
-}
-
-/********************** DotTemplateExp ***********************************/
-
-// Mainly just a placeholder
-
-DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td)
- : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e)
-
-{
- this->td = td;
-}
-
-bool DotTemplateExp::checkType()
-{
- error("%s %s has no type", td->kind(), toChars());
- return true;
-}
-
-bool DotTemplateExp::checkValue()
-{
- error("%s %s has no value", td->kind(), toChars());
- return true;
-}
-
-/************************************************************/
-
-DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads)
- : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e)
-{
- //printf("DotVarExp()\n");
- this->var = var;
- this->hasOverloads = var->isVarDeclaration() ? false : hasOverloads;
-}
-
-bool DotVarExp::isLvalue()
-{
- return true;
-}
-
-Expression *DotVarExp::toLvalue(Scope *, Expression *)
-{
- //printf("DotVarExp::toLvalue(%s)\n", toChars());
- return this;
-}
-
-/***********************************************
- * Mark variable v as modified if it is inside a constructor that var
- * is a field in.
- */
-int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1)
-{
- //printf("modifyFieldVar(var = %s)\n", var->toChars());
- Dsymbol *s = sc->func;
- while (1)
- {
- FuncDeclaration *fd = NULL;
- if (s)
- fd = s->isFuncDeclaration();
- if (fd &&
- ((fd->isCtorDeclaration() && var->isField()) ||
- (fd->isStaticCtorDeclaration() && !var->isField())) &&
- fd->toParent2() == var->toParent2() &&
- (!e1 || e1->op == TOKthis)
- )
- {
- bool result = true;
-
- var->ctorinit = true;
- //printf("setting ctorinit\n");
-
- if (var->isField() && sc->fieldinit && !sc->intypeof)
- {
- assert(e1);
- bool mustInit = ((var->storage_class & STCnodefaultctor) != 0 ||
- var->type->needsNested());
-
- size_t dim = sc->fieldinit_dim;
- AggregateDeclaration *ad = fd->isMember2();
- assert(ad);
- size_t i;
- for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
- {
- if (ad->fields[i] == var)
- break;
- }
- assert(i < dim);
- unsigned fi = sc->fieldinit[i];
-
- if (fi & CSXthis_ctor)
- {
- if (var->type->isMutable() && e1->type->isMutable())
- result = false;
- else
- {
- const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
- ::error(loc, "%s field `%s` initialized multiple times", modStr, var->toChars());
- }
- }
- else if (sc->noctor || (fi & CSXlabel))
- {
- if (!mustInit && var->type->isMutable() && e1->type->isMutable())
- result = false;
- else
- {
- const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
- ::error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var->toChars());
- }
- }
- sc->fieldinit[i] |= CSXthis_ctor;
- if (var->overlapped) // Bugzilla 15258
- {
- for (size_t j = 0; j < ad->fields.length; j++)
- {
- VarDeclaration *v = ad->fields[j];
- if (v == var || !var->isOverlappedWith(v))
- continue;
- v->ctorinit = true;
- sc->fieldinit[j] = CSXthis_ctor;
- }
- }
- }
- else if (fd != sc->func)
- {
- if (var->type->isMutable())
- result = false;
- else if (sc->func->fes)
- {
- const char *p = var->isField() ? "field" : var->kind();
- ::error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
- MODtoChars(var->type->mod), p, var->toChars());
- }
- else
- {
- const char *p = var->isField() ? "field" : var->kind();
- ::error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
- MODtoChars(var->type->mod), p, var->toChars(), sc->func->toChars());
- }
- }
- return result;
- }
- else
- {
- if (s)
- {
- s = s->toParent2();
- continue;
- }
- }
- break;
- }
- return false;
-}
-
-int DotVarExp::checkModifiable(Scope *sc, int flag)
-{
- //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type->toChars());
- if (checkUnsafeAccess(sc, this, false, !flag))
- return 2;
-
- if (e1->op == TOKthis)
- return var->checkModify(loc, sc, type, e1, flag);
-
- //printf("\te1 = %s\n", e1->toChars());
- return e1->checkModifiable(sc, flag);
-}
-
-Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- return Expression::modifiableLvalue(sc, e);
-}
-
-/************************************************************/
-
-/* Things like:
- * foo.bar!(args)
- */
-
-DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs)
- : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
-{
- //printf("DotTemplateInstanceExp()\n");
- this->ti = new TemplateInstance(loc, name);
- this->ti->tiargs = tiargs;
-}
-
-DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti)
- : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
-{
- this->ti = ti;
-}
-
-Expression *DotTemplateInstanceExp::syntaxCopy()
-{
- return new DotTemplateInstanceExp(loc,
- e1->syntaxCopy(),
- ti->name,
- TemplateInstance::arraySyntaxCopy(ti->tiargs));
-}
-
-bool DotTemplateInstanceExp::findTempDecl(Scope *sc)
-{
- if (ti->tempdecl)
- return true;
-
- Expression *e = new DotIdExp(loc, e1, ti->name);
- e = expressionSemantic(e, sc);
- if (e->op == TOKdot)
- e = ((DotExp *)e)->e2;
-
- Dsymbol *s = NULL;
- switch (e->op)
- {
- case TOKoverloadset: s = ((OverExp *)e)->vars; break;
- case TOKdottd: s = ((DotTemplateExp *)e)->td; break;
- case TOKscope: s = ((ScopeExp *)e)->sds; break;
- case TOKdotvar: s = ((DotVarExp *)e)->var; break;
- case TOKvar: s = ((VarExp *)e)->var; break;
- default: return false;
- }
- return ti->updateTempDecl(sc, s);
-}
-
-/************************************************************/
-
-DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, bool hasOverloads)
- : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e)
-{
- this->func = f;
- this->hasOverloads = hasOverloads;
-}
-
-/************************************************************/
-
-DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s)
- : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e)
-{
- this->sym = s;
- this->type = NULL;
-}
-
-/************************************************************/
-
-CallExp::CallExp(Loc loc, Expression *e, Expressions *exps)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- this->arguments = exps;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp::CallExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- this->arguments = NULL;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp::CallExp(Loc loc, Expression *e, Expression *earg1)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- Expressions *arguments = new Expressions();
- if (earg1)
- {
- arguments->setDim(1);
- (*arguments)[0] = earg1;
- }
- this->arguments = arguments;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- Expressions *arguments = new Expressions();
- arguments->setDim(2);
- (*arguments)[0] = earg1;
- (*arguments)[1] = earg2;
-
- this->arguments = arguments;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp *CallExp::create(Loc loc, Expression *e, Expressions *exps)
-{
- return new CallExp(loc, e, exps);
-}
-
-CallExp *CallExp::create(Loc loc, Expression *e)
-{
- return new CallExp(loc, e);
-}
-
-CallExp *CallExp::create(Loc loc, Expression *e, Expression *earg1)
-{
- return new CallExp(loc, e, earg1);
-}
-
-Expression *CallExp::syntaxCopy()
-{
- return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
-}
-
-bool CallExp::isLvalue()
-{
- Type *tb = e1->type->toBasetype();
- if (tb->ty == Tdelegate || tb->ty == Tpointer)
- tb = tb->nextOf();
- if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref)
- {
- if (e1->op == TOKdotvar)
- if (((DotVarExp *)e1)->var->isCtorDeclaration())
- return false;
- return true; // function returns a reference
- }
- return false;
-}
-
-Expression *CallExp::toLvalue(Scope *sc, Expression *e)
-{
- if (isLvalue())
- return this;
- return Expression::toLvalue(sc, e);
-}
-
-Expression *CallExp::addDtorHook(Scope *sc)
-{
- /* Only need to add dtor hook if it's a type that needs destruction.
- * Use same logic as VarDeclaration::callScopeDtor()
- */
-
- if (e1->type && e1->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)e1->type;
- if (tf->isref)
- return this;
- }
-
- Type *tv = type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tv;
- StructDeclaration *sd = ts->sym;
- if (sd->dtor)
- {
- /* Type needs destruction, so declare a tmp
- * which the back end will recognize and call dtor on
- */
- VarDeclaration *tmp = copyToTemp(0, "__tmpfordtor", this);
- DeclarationExp *de = new DeclarationExp(loc, tmp);
- VarExp *ve = new VarExp(loc, tmp);
- Expression *e = new CommaExp(loc, de, ve);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- return this;
-}
-
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL)
-{
- if (e->op == TOKaddress)
- {
- Expression *ae1 = ((AddrExp *)e)->e1;
- if (ae1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)ae1;
- if (hasOverloads)
- *hasOverloads = ve->hasOverloads;
- return ve->var->isFuncDeclaration();
- }
- if (ae1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)ae1;
- if (hasOverloads)
- *hasOverloads = dve->hasOverloads;
- return dve->var->isFuncDeclaration();
- }
- }
- else
- {
- if (e->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)e;
- if (hasOverloads)
- *hasOverloads = soe->hasOverloads;
- return soe->var->isFuncDeclaration();
- }
- if (e->op == TOKdelegate)
- {
- DelegateExp *dge = (DelegateExp *)e;
- if (hasOverloads)
- *hasOverloads = dge->hasOverloads;
- return dge->func->isFuncDeclaration();
- }
- }
- return NULL;
-}
-
-/************************************************************/
-
-AddrExp::AddrExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
-{
-}
-
-AddrExp::AddrExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
-{
- type = t;
-}
-
-/************************************************************/
-
-PtrExp::PtrExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
-{
-// if (e->type)
-// type = ((TypePointer *)e->type)->next;
-}
-
-PtrExp::PtrExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
-{
- type = t;
-}
-
-bool PtrExp::isLvalue()
-{
- return true;
-}
-
-Expression *PtrExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-int PtrExp::checkModifiable(Scope *sc, int flag)
-{
- if (e1->op == TOKsymoff)
- { SymOffExp *se = (SymOffExp *)e1;
- return se->var->checkModify(loc, sc, type, NULL, flag);
- }
- else if (e1->op == TOKaddress)
- {
- AddrExp *ae = (AddrExp *)e1;
- return ae->e1->checkModifiable(sc, flag);
- }
- return 1;
-}
-
-Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars());
- return Expression::modifiableLvalue(sc, e);
-}
-
-/************************************************************/
-
-NegExp::NegExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKneg, sizeof(NegExp), e)
-{
-}
-
-/************************************************************/
-
-UAddExp::UAddExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKuadd, sizeof(UAddExp), e)
-{
-}
-
-/************************************************************/
-
-ComExp::ComExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKtilde, sizeof(ComExp), e)
-{
-}
-
-/************************************************************/
-
-NotExp::NotExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKnot, sizeof(NotExp), e)
-{
-}
-
-/************************************************************/
-
-DeleteExp::DeleteExp(Loc loc, Expression *e, bool isRAII)
- : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e)
-{
- this->isRAII = isRAII;
-}
-
-Expression *DeleteExp::toBoolean(Scope *)
-{
- error("delete does not give a boolean result");
- return new ErrorExp();
-}
-
-/************************************************************/
-
-CastExp::CastExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKcast, sizeof(CastExp), e)
-{
- this->to = t;
- this->mod = (unsigned char)~0;
-}
-
-/* For cast(const) and cast(immutable)
- */
-CastExp::CastExp(Loc loc, Expression *e, unsigned char mod)
- : UnaExp(loc, TOKcast, sizeof(CastExp), e)
-{
- this->to = NULL;
- this->mod = mod;
-}
-
-Expression *CastExp::syntaxCopy()
-{
- return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy())
- : new CastExp(loc, e1->syntaxCopy(), mod);
-}
-
-/************************************************************/
-
-VectorExp::VectorExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKvector, sizeof(VectorExp), e)
-{
- assert(t->ty == Tvector);
- to = (TypeVector *)t;
- dim = ~0;
- ownedByCtfe = OWNEDcode;
-}
-
-VectorExp *VectorExp::create(Loc loc, Expression *e, Type *t)
-{
- return new VectorExp(loc, e, t);
-}
-
-Expression *VectorExp::syntaxCopy()
-{
- return new VectorExp(loc, e1->syntaxCopy(), to->syntaxCopy());
-}
-
-/************************************************************/
-
-VectorArrayExp::VectorArrayExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKvectorarray, sizeof(VectorArrayExp), e1)
-{
-}
-
-bool VectorArrayExp::isLvalue()
-{
- return e1->isLvalue();
-}
-
-Expression *VectorArrayExp::toLvalue(Scope *sc, Expression *e)
-{
- e1 = e1->toLvalue(sc, e);
- return this;
-}
-
-/************************************************************/
-
-SliceExp::SliceExp(Loc loc, Expression *e1, IntervalExp *ie)
- : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
-{
- this->upr = ie ? ie->upr : NULL;
- this->lwr = ie ? ie->lwr : NULL;
- lengthVar = NULL;
- upperIsInBounds = false;
- lowerIsLessThanUpper = false;
- arrayop = false;
-}
-
-SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr)
- : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
-{
- this->upr = upr;
- this->lwr = lwr;
- lengthVar = NULL;
- upperIsInBounds = false;
- lowerIsLessThanUpper = false;
- arrayop = false;
-}
-
-Expression *SliceExp::syntaxCopy()
-{
- SliceExp *se = new SliceExp(loc, e1->syntaxCopy(),
- lwr ? lwr->syntaxCopy() : NULL,
- upr ? upr->syntaxCopy() : NULL);
- se->lengthVar = this->lengthVar; // bug7871
- return se;
-}
-
-int SliceExp::checkModifiable(Scope *sc, int flag)
-{
- //printf("SliceExp::checkModifiable %s\n", toChars());
- if (e1->type->ty == Tsarray ||
- (e1->op == TOKindex && e1->type->ty != Tarray) ||
- e1->op == TOKslice)
- {
- return e1->checkModifiable(sc, flag);
- }
- return 1;
-}
-
-bool SliceExp::isLvalue()
-{
- /* slice expression is rvalue in default, but
- * conversion to reference of static array is only allowed.
- */
- return (type && type->toBasetype()->ty == Tsarray);
-}
-
-Expression *SliceExp::toLvalue(Scope *sc, Expression *e)
-{
- //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
- return (type && type->toBasetype()->ty == Tsarray)
- ? this : Expression::toLvalue(sc, e);
-}
-
-Expression *SliceExp::modifiableLvalue(Scope *, Expression *)
-{
- error("slice expression %s is not a modifiable lvalue", toChars());
- return this;
-}
-
-bool SliceExp::isBool(bool result)
-{
- return e1->isBool(result);
-}
-
-/********************** ArrayLength **************************************/
-
-ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1)
-{
-}
-
-/*********************** IntervalExp ********************************/
-
-// Mainly just a placeholder
-
-IntervalExp::IntervalExp(Loc loc, Expression *lwr, Expression *upr)
- : Expression(loc, TOKinterval, sizeof(IntervalExp))
-{
- this->lwr = lwr;
- this->upr = upr;
-}
-
-Expression *IntervalExp::syntaxCopy()
-{
- return new IntervalExp(loc, lwr->syntaxCopy(), upr->syntaxCopy());
-}
-
-/********************** DelegatePtrExp **************************************/
-
-DelegatePtrExp::DelegatePtrExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKdelegateptr, sizeof(DelegatePtrExp), e1)
-{
-}
-
-bool DelegatePtrExp::isLvalue()
-{
- return e1->isLvalue();
-}
-
-Expression *DelegatePtrExp::toLvalue(Scope *sc, Expression *e)
-{
- e1 = e1->toLvalue(sc, e);
- return this;
-}
-
-Expression *DelegatePtrExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- if (sc->func->setUnsafe())
- {
- error("cannot modify delegate pointer in @safe code %s", toChars());
- return new ErrorExp();
- }
- return Expression::modifiableLvalue(sc, e);
-}
-
-/********************** DelegateFuncptrExp **************************************/
-
-DelegateFuncptrExp::DelegateFuncptrExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKdelegatefuncptr, sizeof(DelegateFuncptrExp), e1)
-{
-}
-
-bool DelegateFuncptrExp::isLvalue()
-{
- return e1->isLvalue();
-}
-
-Expression *DelegateFuncptrExp::toLvalue(Scope *sc, Expression *e)
-{
- e1 = e1->toLvalue(sc, e);
- return this;
-}
-
-Expression *DelegateFuncptrExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- if (sc->func->setUnsafe())
- {
- error("cannot modify delegate function pointer in @safe code %s", toChars());
- return new ErrorExp();
- }
- return Expression::modifiableLvalue(sc, e);
-}
-
-/*********************** ArrayExp *************************************/
-
-// e1 [ i1, i2, i3, ... ]
-
-ArrayExp::ArrayExp(Loc loc, Expression *e1, Expression *index)
- : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
-{
- arguments = new Expressions();
- if (index)
- arguments->push(index);
- lengthVar = NULL;
- currentDimension = 0;
-}
-
-ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args)
- : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
-{
- arguments = args;
- lengthVar = NULL;
- currentDimension = 0;
-}
-
-Expression *ArrayExp::syntaxCopy()
-{
- ArrayExp *ae = new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
- ae->lengthVar = this->lengthVar; // bug7871
- return ae;
-}
-
-bool ArrayExp::isLvalue()
-{
- if (type && type->toBasetype()->ty == Tvoid)
- return false;
- return true;
-}
-
-Expression *ArrayExp::toLvalue(Scope *, Expression *)
-{
- if (type && type->toBasetype()->ty == Tvoid)
- error("voids have no value");
- return this;
-}
-
-/************************* DotExp ***********************************/
-
-DotExp::DotExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKdot, sizeof(DotExp), e1, e2)
-{
-}
-
-/************************* CommaExp ***********************************/
-
-CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated)
- : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2)
-{
- isGenerated = generated;
- allowCommaExp = generated;
-}
-
-bool CommaExp::isLvalue()
-{
- return e2->isLvalue();
-}
-
-Expression *CommaExp::toLvalue(Scope *sc, Expression *)
-{
- e2 = e2->toLvalue(sc, NULL);
- return this;
-}
-
-int CommaExp::checkModifiable(Scope *sc, int flag)
-{
- return e2->checkModifiable(sc, flag);
-}
-
-Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- e2 = e2->modifiableLvalue(sc, e);
- return this;
-}
-
-bool CommaExp::isBool(bool result)
-{
- return e2->isBool(result);
-}
-
-Expression *CommaExp::toBoolean(Scope *sc)
-{
- Expression *ex2 = e2->toBoolean(sc);
- if (ex2->op == TOKerror)
- return ex2;
- e2 = ex2;
- type = e2->type;
- return this;
-}
-
-Expression *CommaExp::addDtorHook(Scope *sc)
-{
- e2 = e2->addDtorHook(sc);
- return this;
-}
-
-/************************** IndexExp **********************************/
-
-// e1 [ e2 ]
-
-IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2)
-{
- //printf("IndexExp::IndexExp('%s')\n", toChars());
- lengthVar = NULL;
- modifiable = false; // assume it is an rvalue
- indexIsInBounds = false;
-}
-
-Expression *IndexExp::syntaxCopy()
-{
- IndexExp *ie = new IndexExp(loc, e1->syntaxCopy(), e2->syntaxCopy());
- ie->lengthVar = this->lengthVar; // bug7871
- return ie;
-}
-
-bool IndexExp::isLvalue()
-{
- return true;
-}
-
-Expression *IndexExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-int IndexExp::checkModifiable(Scope *sc, int flag)
-{
- if (e1->type->ty == Tsarray ||
- e1->type->ty == Taarray ||
- (e1->op == TOKindex && e1->type->ty != Tarray) ||
- e1->op == TOKslice)
- {
- return e1->checkModifiable(sc, flag);
- }
- return 1;
-}
-
-Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
- Expression *ex = markSettingAAElem();
- if (ex->op == TOKerror)
- return ex;
-
- return Expression::modifiableLvalue(sc, e);
-}
-
-Expression *IndexExp::markSettingAAElem()
-{
- if (e1->type->toBasetype()->ty == Taarray)
- {
- Type *t2b = e2->type->toBasetype();
- if (t2b->ty == Tarray && t2b->nextOf()->isMutable())
- {
- error("associative arrays can only be assigned values with immutable keys, not %s", e2->type->toChars());
- return new ErrorExp();
- }
- modifiable = true;
-
- if (e1->op == TOKindex)
- {
- Expression *ex = ((IndexExp *)e1)->markSettingAAElem();
- if (ex->op == TOKerror)
- return ex;
- assert(ex == e1);
- }
- }
- return this;
-}
-
-/************************* PostExp ***********************************/
-
-PostExp::PostExp(TOK op, Loc loc, Expression *e)
- : BinExp(loc, op, sizeof(PostExp), e,
- new IntegerExp(loc, 1, Type::tint32))
-{
-}
-
-/************************* PreExp ***********************************/
-
-PreExp::PreExp(TOK op, Loc loc, Expression *e)
- : UnaExp(loc, op, sizeof(PreExp), e)
-{
-}
-
-/************************************************************/
-
-/* op can be TOKassign, TOKconstruct, or TOKblit */
-
-AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2)
-{
- memset = 0;
-}
-
-bool AssignExp::isLvalue()
-{
- // Array-op 'x[] = y[]' should make an rvalue.
- // Setting array length 'x.length = v' should make an rvalue.
- if (e1->op == TOKslice ||
- e1->op == TOKarraylength)
- {
- return false;
- }
- return true;
-}
-
-Expression *AssignExp::toLvalue(Scope *sc, Expression *ex)
-{
- if (e1->op == TOKslice ||
- e1->op == TOKarraylength)
- {
- return Expression::toLvalue(sc, ex);
- }
-
- /* In front-end level, AssignExp should make an lvalue of e1.
- * Taking the address of e1 will be handled in low level layer,
- * so this function does nothing.
- */
- return this;
-}
-
-Expression *AssignExp::toBoolean(Scope *)
-{
- // Things like:
- // if (a = b) ...
- // are usually mistakes.
-
- error("assignment cannot be used as a condition, perhaps == was meant?");
- return new ErrorExp();
-}
-
-/************************************************************/
-
-ConstructExp::ConstructExp(Loc loc, Expression *e1, Expression *e2)
- : AssignExp(loc, e1, e2)
-{
- op = TOKconstruct;
-}
-
-ConstructExp::ConstructExp(Loc loc, VarDeclaration *v, Expression *e2)
- : AssignExp(loc, new VarExp(loc, v), e2)
-{
- assert(v->type && e1->type);
- op = TOKconstruct;
-
- if (v->storage_class & (STCref | STCout))
- memset |= referenceInit;
-}
-
-/************************************************************/
-
-BlitExp::BlitExp(Loc loc, Expression *e1, Expression *e2)
- : AssignExp(loc, e1, e2)
-{
- op = TOKblit;
-}
-
-BlitExp::BlitExp(Loc loc, VarDeclaration *v, Expression *e2)
- : AssignExp(loc, new VarExp(loc, v), e2)
-{
- assert(v->type && e1->type);
- op = TOKblit;
-
- if (v->storage_class & (STCref | STCout))
- memset |= referenceInit;
-}
-
-/************************************************************/
-
-AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2)
-{
-}
-
-/***************** PowAssignExp *******************************************/
-
-PowAssignExp::PowAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKpowass, sizeof(PowAssignExp), e1, e2)
-{
-}
-
-/************************* AddExp *****************************/
-
-AddExp::AddExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MinExp::MinExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2)
-{
-}
-
-/************************* CatExp *****************************/
-
-CatExp::CatExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MulExp::MulExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-DivExp::DivExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ModExp::ModExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-PowExp::PowExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKpow, sizeof(PowExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-AndExp::AndExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKand, sizeof(AndExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-OrExp::OrExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKor, sizeof(OrExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-XorExp::XorExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-LogicalExp::LogicalExp(Loc loc, TOK op, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(LogicalExp), e1, e2)
-{
-}
-
-Expression *LogicalExp::toBoolean(Scope *sc)
-{
- Expression *ex2 = e2->toBoolean(sc);
- if (ex2->op == TOKerror)
- return ex2;
- e2 = ex2;
- return this;
-}
-
-/************************************************************/
-
-InExp::InExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKin, sizeof(InExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-/* This deletes the key e1 from the associative array e2
- */
-
-RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2)
-{
- type = Type::tbool;
-}
-
-/************************************************************/
-
-CmpExp::CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(CmpExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-EqualExp::EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(EqualExp), e1, e2)
-{
- assert(op == TOKequal || op == TOKnotequal);
-}
-
-/************************************************************/
-
-IdentityExp::IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(IdentityExp), e1, e2)
-{
-}
-
-/****************************************************************/
-
-CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2)
- : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2)
-{
- this->econd = econd;
-}
-
-Expression *CondExp::syntaxCopy()
-{
- return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy());
-}
-
-void CondExp::hookDtors(Scope *sc)
-{
- class DtorVisitor : public StoppableVisitor
- {
- public:
- Scope *sc;
- CondExp *ce;
- VarDeclaration *vcond;
- bool isThen;
-
- DtorVisitor(Scope *sc, CondExp *ce)
- {
- this->sc = sc;
- this->ce = ce;
- this->vcond = NULL;
- }
-
- void visit(Expression *)
- {
- //printf("(e = %s)\n", e->toChars());
- }
-
- void visit(DeclarationExp *e)
- {
- VarDeclaration *v = e->declaration->isVarDeclaration();
- if (v && !v->isDataseg())
- {
- if (v->_init)
- {
- ExpInitializer *ei = v->_init->isExpInitializer();
- if (ei)
- ei->exp->accept(this);
- }
-
- if (v->needsScopeDtor())
- {
- if (!vcond)
- {
- vcond = copyToTemp(STCvolatile, "__cond", ce->econd);
- dsymbolSemantic(vcond, sc);
-
- Expression *de = new DeclarationExp(ce->econd->loc, vcond);
- de = expressionSemantic(de, sc);
-
- Expression *ve = new VarExp(ce->econd->loc, vcond);
- ce->econd = Expression::combine(de, ve);
- }
-
- //printf("\t++v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
- Expression *ve = new VarExp(vcond->loc, vcond);
- if (isThen)
- v->edtor = new LogicalExp(v->edtor->loc, TOKandand, ve, v->edtor);
- else
- v->edtor = new LogicalExp(v->edtor->loc, TOKoror, ve, v->edtor);
- v->edtor = expressionSemantic(v->edtor, sc);
- //printf("\t--v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
- }
- }
- }
- };
-
- DtorVisitor v(sc, this);
- //printf("+%s\n", toChars());
- v.isThen = true; walkPostorder(e1, &v);
- v.isThen = false; walkPostorder(e2, &v);
- //printf("-%s\n", toChars());
-}
-
-bool CondExp::isLvalue()
-{
- return e1->isLvalue() && e2->isLvalue();
-}
-
-
-Expression *CondExp::toLvalue(Scope *sc, Expression *)
-{
- // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
- CondExp *e = (CondExp *)copy();
- e->e1 = e1->toLvalue(sc, NULL)->addressOf();
- e->e2 = e2->toLvalue(sc, NULL)->addressOf();
- e->type = type->pointerTo();
- return new PtrExp(loc, e, type);
-}
-
-int CondExp::checkModifiable(Scope *sc, int flag)
-{
- return e1->checkModifiable(sc, flag) && e2->checkModifiable(sc, flag);
-}
-
-Expression *CondExp::modifiableLvalue(Scope *sc, Expression *)
-{
- //error("conditional expression %s is not a modifiable lvalue", toChars());
- e1 = e1->modifiableLvalue(sc, e1);
- e2 = e2->modifiableLvalue(sc, e2);
- return toLvalue(sc, this);
-}
-
-Expression *CondExp::toBoolean(Scope *sc)
-{
- Expression *ex1 = e1->toBoolean(sc);
- Expression *ex2 = e2->toBoolean(sc);
- if (ex1->op == TOKerror)
- return ex1;
- if (ex2->op == TOKerror)
- return ex2;
- e1 = ex1;
- e2 = ex2;
- return this;
-}
-
-/****************************************************************/
-
-DefaultInitExp::DefaultInitExp(Loc loc, TOK subop, int size)
- : Expression(loc, TOKdefault, size)
-{
- this->subop = subop;
-}
-
-/****************************************************************/
-
-FileInitExp::FileInitExp(Loc loc, TOK tok)
- : DefaultInitExp(loc, tok, sizeof(FileInitExp))
-{
-}
-
-Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- //printf("FileInitExp::resolve() %s\n", toChars());
- const char *s;
- if (subop == TOKfilefullpath)
- s = FileName::toAbsolute(loc.filename != NULL ? loc.filename : sc->_module->srcfile->name->toChars());
- else
- s = loc.filename != NULL ? loc.filename : sc->_module->ident->toChars();
-
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e = e->castTo(sc, type);
- return e;
-}
-
-/****************************************************************/
-
-LineInitExp::LineInitExp(Loc loc)
- : DefaultInitExp(loc, TOKline, sizeof(LineInitExp))
-{
-}
-
-Expression *LineInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32);
- e = e->castTo(sc, type);
- return e;
-}
-
-/****************************************************************/
-
-ModuleInitExp::ModuleInitExp(Loc loc)
- : DefaultInitExp(loc, TOKmodulestring, sizeof(ModuleInitExp))
-{
-}
-
-Expression *ModuleInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- const char *s;
- if (sc->callsc)
- s = sc->callsc->_module->toPrettyChars();
- else
- s = sc->_module->toPrettyChars();
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e = e->castTo(sc, type);
- return e;
-}
-
-/****************************************************************/
-
-FuncInitExp::FuncInitExp(Loc loc)
- : DefaultInitExp(loc, TOKfuncstring, sizeof(FuncInitExp))
-{
-}
-
-Expression *FuncInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- const char *s;
- if (sc->callsc && sc->callsc->func)
- s = sc->callsc->func->Dsymbol::toPrettyChars();
- else if (sc->func)
- s = sc->func->Dsymbol::toPrettyChars();
- else
- s = "";
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e->type = Type::tstring;
- return e;
-}
-
-/****************************************************************/
-
-PrettyFuncInitExp::PrettyFuncInitExp(Loc loc)
- : DefaultInitExp(loc, TOKprettyfunc, sizeof(PrettyFuncInitExp))
-{
-}
-
-Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- FuncDeclaration *fd;
- if (sc->callsc && sc->callsc->func)
- fd = sc->callsc->func;
- else
- fd = sc->func;
-
- const char *s;
- if (fd)
- {
- const char *funcStr = fd->Dsymbol::toPrettyChars();
- OutBuffer buf;
- functionToBufferWithIdent((TypeFunction *)fd->type, &buf, funcStr);
- s = buf.extractChars();
- }
- else
- {
- s = "";
- }
-
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e->type = Type::tstring;
- return e;
-}
-
-Expression *BinExp::reorderSettingAAElem(Scope *sc)
-{
- BinExp *be = this;
-
- if (be->e1->op != TOKindex)
- return be;
- IndexExp *ie = (IndexExp *)be->e1;
- if (ie->e1->type->toBasetype()->ty != Taarray)
- return be;
-
- /* Fix evaluation order of setting AA element. (Bugzilla 3825)
- * Rewrite:
- * aa[k1][k2][k3] op= val;
- * as:
- * auto ref __aatmp = aa;
- * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
- * auto ref __aaval = val;
- * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
- */
-
- Expression *e0 = NULL;
- while (1)
- {
- Expression *de = NULL;
- ie->e2 = extractSideEffect(sc, "__aakey", &de, ie->e2);
- e0 = Expression::combine(de, e0);
-
- Expression *ie1 = ie->e1;
- if (ie1->op != TOKindex ||
- ((IndexExp *)ie1)->e1->type->toBasetype()->ty != Taarray)
- {
- break;
- }
- ie = (IndexExp *)ie1;
- }
- assert(ie->e1->type->toBasetype()->ty == Taarray);
-
- Expression *de = NULL;
- ie->e1 = extractSideEffect(sc, "__aatmp", &de, ie->e1);
- e0 = Expression::combine(de, e0);
-
- be->e2 = extractSideEffect(sc, "__aaval", &e0, be->e2, true);
-
- //printf("-e0 = %s, be = %s\n", e0->toChars(), be->toChars());
- return Expression::combine(e0, be);
-}