aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/expressionsem.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/expressionsem.c')
-rw-r--r--gcc/d/dmd/expressionsem.c10740
1 files changed, 0 insertions, 10740 deletions
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
deleted file mode 100644
index 5ae5fe6..0000000
--- a/gcc/d/dmd/expressionsem.c
+++ /dev/null
@@ -1,10740 +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
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/root.h"
-
-#include "mars.h"
-#include "mangle.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 "nspace.h"
-#include "ctfe.h"
-#include "target.h"
-
-bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2);
-bool isArrayOpValid(Expression *e);
-Expression *expandVar(int result, VarDeclaration *v);
-bool checkAssignEscape(Scope *sc, Expression *e, bool gag);
-bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
-bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
-bool checkNestedRef(Dsymbol *s, Dsymbol *p);
-bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0);
-bool symbolIsVisible(Module *mod, Dsymbol *s);
-bool symbolIsVisible(Scope *sc, Dsymbol *s);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
-Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
-char *MODtoChars(MOD mod);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-MOD MODmerge(MOD mod1, MOD mod2);
-MATCH MODmethodConv(MOD modfrom, MOD modto);
-void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
-
-void unSpeculative(Scope *sc, RootObject *o);
-bool isDotOpDispatch(Expression *e);
-bool isNeedThisScope(Scope *sc, Declaration *d);
-bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
-bool isSafeCast(Expression *e, Type *tfrom, Type *tto);
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
-Expression *callCpCtor(Scope *sc, Expression *e);
-
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-
-bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
-bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
-
-/********************************************************
- * Perform semantic analysis and CTFE on expressions to produce
- * a string.
- * Params:
- * buf = append generated string to buffer
- * sc = context
- * exps = array of Expressions
- * Returns:
- * true on error
- */
-bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps)
-{
- if (!exps)
- return false;
-
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *ex = (*exps)[i];
- if (!ex)
- continue;
- Scope *sc2 = sc->startCTFE();
- Expression *e2 = expressionSemantic(ex, sc2);
- Expression *e3 = resolveProperties(sc2, e2);
- sc2->endCTFE();
-
- // allowed to contain types as well as expressions
- Expression *e4 = ctfeInterpretForPragmaMsg(e3);
- if (!e4 || e4->op == TOKerror)
- return true;
-
- // expand tuple
- if (TupleExp *te = e4->isTupleExp())
- {
- if (expressionsToString(buf, sc, te->exps))
- return true;
- continue;
- }
- // char literals exp `.toStringExp` return `null` but we cant override it
- // because in most contexts we don't want the conversion to succeed.
- IntegerExp *ie = e4->isIntegerExp();
- const TY ty = (ie && ie->type) ? ie->type->ty : (TY)Terror;
- if (ty == Tchar || ty == Twchar || ty == Tdchar)
- {
- TypeSArray *tsa = new TypeSArray(ie->type, new IntegerExp(ex->loc, 1, Type::tint32));
- e4 = new ArrayLiteralExp(ex->loc, tsa, ie);
- }
-
- if (StringExp *se = e4->toStringExp())
- buf.writestring(se->toUTF8(sc)->toPtr());
- else
- buf.writestring(e4->toChars());
- }
- return false;
-}
-
-/***********************************************************
- * Resolve `exp` as a compile-time known string.
- * Params:
- * sc = scope
- * exp = Expression which expected as a string
- * s = What the string is expected for, will be used in error diagnostic.
- * Returns:
- * String literal, or `null` if error happens.
- */
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s)
-{
- sc = sc->startCTFE();
- exp = expressionSemantic(exp, sc);
- exp = resolveProperties(sc, exp);
- sc = sc->endCTFE();
-
- if (exp->op == TOKerror)
- return NULL;
-
- Expression *e = exp;
- if (exp->type->isString())
- {
- e = e->ctfeInterpret();
- if (e->op == TOKerror)
- return NULL;
- }
-
- StringExp *se = e->toStringExp();
- if (!se)
- {
- exp->error("string expected for %s, not (%s) of type %s",
- s, exp->toChars(), exp->type->toChars());
- return NULL;
- }
- return se;
-}
-
-/****************************************************************/
-
-static Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
-{
- Expression *e0;
- Expression *e1 = Expression::extractLast(ue->e1, &e0);
- // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
-
- if (!isTrivialExp(e1))
- {
- /* Even if opDollar is needed, 'e1' should be evaluate only once. So
- * Rewrite:
- * e1.opIndex( ... use of $ ... )
- * e1.opSlice( ... use of $ ... )
- * as:
- * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
- * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
- */
- e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
- assert(e1->op == TOKvar);
- VarExp *ve = (VarExp *)e1;
- ve->var->storage_class |= STCexptemp; // lifetime limited to expression
- }
- ue->e1 = e1;
- return e0;
-}
-
-/**************************************
- * Runs semantic on ae->arguments. Declares temporary variables
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
-{
- assert(!ae->lengthVar);
-
- *pe0 = NULL;
-
- AggregateDeclaration *ad = isAggregate(ae->e1->type);
- Dsymbol *slice = search_function(ad, Id::slice);
- //printf("slice = %s %s\n", slice->kind(), slice->toChars());
-
- for (size_t i = 0; i < ae->arguments->length; i++)
- {
- if (i == 0)
- *pe0 = extractOpDollarSideEffect(sc, ae);
-
- Expression *e = (*ae->arguments)[i];
- if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
- {
- Lfallback:
- if (ae->arguments->length == 1)
- return NULL;
- ae->error("multi-dimensional slicing requires template opSlice");
- return new ErrorExp();
- }
- //printf("[%d] e = %s\n", i, e->toChars());
-
- // Create scope for '$' variable for this dimension
- ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
- sym->loc = ae->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- ae->lengthVar = NULL; // Create it only if required
- ae->currentDimension = i; // Dimension for $, if required
-
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
-
- if (ae->lengthVar && sc->func)
- {
- // If $ was used, declare it now
- Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = expressionSemantic(de, sc);
- *pe0 = Expression::combine(*pe0, de);
- }
- sc = sc->pop();
-
- if (e->op == TOKinterval)
- {
- IntervalExp *ie = (IntervalExp *)e;
-
- Objects *tiargs = new Objects();
- Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
- edim = expressionSemantic(edim, sc);
- tiargs->push(edim);
-
- Expressions *fargs = new Expressions();
- fargs->push(ie->lwr);
- fargs->push(ie->upr);
-
- unsigned xerrors = global.startGagging();
- sc = sc->push();
- FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
- sc = sc->pop();
- global.endGagging(xerrors);
- if (!fslice)
- goto Lfallback;
-
- e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
- e = new CallExp(ae->loc, e, fargs);
- e = expressionSemantic(e, sc);
- }
-
- if (!e->type)
- {
- ae->error("%s has no value", e->toChars());
- e = new ErrorExp();
- }
- if (e->op == TOKerror)
- return e;
-
- (*ae->arguments)[i] = e;
- }
-
- return ae;
-}
-
-/**************************************
- * Runs semantic on se->lwr and se->upr. Declares a temporary variable
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
-{
- //assert(!ae->lengthVar);
- if (!ie)
- return ae;
-
- VarDeclaration *lengthVar = ae->lengthVar;
-
- // create scope for '$'
- ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
- sym->loc = ae->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- for (size_t i = 0; i < 2; ++i)
- {
- Expression *e = i == 0 ? ie->lwr : ie->upr;
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- if (!e->type)
- {
- ae->error("%s has no value", e->toChars());
- return new ErrorExp();
- }
- (i == 0 ? ie->lwr : ie->upr) = e;
- }
-
- if (lengthVar != ae->lengthVar && sc->func)
- {
- // If $ was used, declare it now
- Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = expressionSemantic(de, sc);
- *pe0 = Expression::combine(*pe0, de);
- }
- sc = sc->pop();
-
- return ae;
-}
-
-/******************************
- * Perform semantic() on an array of Expressions.
- */
-
-bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
-{
- bool err = false;
- if (exps)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (e)
- {
- e = expressionSemantic(e, sc);
- if (e->op == TOKerror)
- err = true;
- if (preserveErrors || e->op != TOKerror)
- (*exps)[i] = e;
- }
- }
- }
- return err;
-}
-
-/******************************
- * Check the tail CallExp is really property function call.
- */
-static bool checkPropertyCall(Expression *e)
-{
- while (e->op == TOKcomma)
- e = ((CommaExp *)e)->e2;
-
- if (e->op == TOKcall)
- {
- CallExp *ce = (CallExp *)e;
- TypeFunction *tf;
- if (ce->f)
- {
- tf = (TypeFunction *)ce->f->type;
- /* If a forward reference to ce->f, try to resolve it
- */
- if (!tf->deco && ce->f->semanticRun < PASSsemanticdone)
- {
- dsymbolSemantic(ce->f, NULL);
- tf = (TypeFunction *)ce->f->type;
- }
- }
- else if (ce->e1->type->ty == Tfunction)
- tf = (TypeFunction *)ce->e1->type;
- else if (ce->e1->type->ty == Tdelegate)
- tf = (TypeFunction *)ce->e1->type->nextOf();
- else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
- tf = (TypeFunction *)ce->e1->type->nextOf();
- else
- assert(0);
- }
- return false;
-}
-
-// TODO: merge with Scope::search::searchScopes()
-static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
-{
- Dsymbol *s = NULL;
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (!scx->scopesym)
- continue;
- if (scx->scopesym->isModule())
- flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
- s = scx->scopesym->search(loc, ident, flags);
- if (s)
- {
- // overload set contains only module scope symbols.
- if (s->isOverloadSet())
- break;
- // selective/renamed imports also be picked up
- if (AliasDeclaration *ad = s->isAliasDeclaration())
- {
- if (ad->_import)
- break;
- }
- // See only module scope symbols for UFCS target.
- Dsymbol *p = s->toParent2();
- if (p && p->isModule())
- break;
- }
- s = NULL;
-
- // Stop when we hit a module, but keep going if that is not just under the global scope
- if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
- break;
- }
- return s;
-}
-
-/******************************
- * Find symbol in accordance with the UFCS name look up rule
- */
-
-static Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
-{
- //printf("searchUFCS(ident = %s)\n", ident->toChars());
- Loc loc = ue->loc;
- int flags = 0;
- Dsymbol *s = NULL;
-
- if (sc->flags & SCOPEignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
-
- // First look in local scopes
- s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
- if (!s)
- {
- // Second look in imported modules
- s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
- }
-
- if (!s)
- return ue->e1->type->Type::getProperty(loc, ident, 0);
-
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- TemplateDeclaration *td = getFuncTemplateDecl(f);
- if (td)
- {
- if (td->overroot)
- td = td->overroot;
- s = td;
- }
- }
-
- if (ue->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
- TemplateInstance *ti = new TemplateInstance(loc, s->ident);
- ti->tiargs = dti->ti->tiargs; // for better diagnostic message
- if (!ti->updateTempDecl(sc, s))
- return new ErrorExp();
- return new ScopeExp(loc, ti);
- }
- else
- {
- //printf("-searchUFCS() %s\n", s->toChars());
- return new DsymbolExp(loc, s);
- }
-}
-
-/******************************
- * Pull out callable entity with UFCS.
- */
-
-static Expression *resolveUFCS(Scope *sc, CallExp *ce)
-{
- Loc loc = ce->loc;
- Expression *eleft;
- Expression *e;
-
- if (ce->e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)ce->e1;
- Identifier *ident = die->ident;
-
- Expression *ex = semanticX(die, sc);
- if (ex != die)
- {
- ce->e1 = ex;
- return NULL;
- }
- eleft = die->e1;
-
- Type *t = eleft->type->toBasetype();
- if (t->ty == Tarray || t->ty == Tsarray ||
- t->ty == Tnull || (t->isTypeBasic() && t->ty != Tvoid))
- {
- /* Built-in types and arrays have no callable properties, so do shortcut.
- * It is necessary in: e.init()
- */
- }
- else if (t->ty == Taarray)
- {
- if (ident == Id::remove)
- {
- /* Transform:
- * aa.remove(arg) into delete aa[arg]
- */
- if (!ce->arguments || ce->arguments->length != 1)
- {
- ce->error("expected key as argument to aa.remove()");
- return new ErrorExp();
- }
- if (!eleft->type->isMutable())
- {
- ce->error("cannot remove key from %s associative array %s",
- MODtoChars(t->mod), eleft->toChars());
- return new ErrorExp();
- }
- Expression *key = (*ce->arguments)[0];
- key = expressionSemantic(key, sc);
- key = resolveProperties(sc, key);
-
- TypeAArray *taa = (TypeAArray *)t;
- key = key->implicitCastTo(sc, taa->index);
-
- if (key->checkValue())
- return new ErrorExp();
-
- semanticTypeInfo(sc, taa->index);
-
- return new RemoveExp(loc, eleft, key);
- }
- }
- else
- {
- if (Expression *ey = semanticY(die, sc, 1))
- {
- if (ey->op == TOKerror)
- return ey;
- ce->e1 = ey;
- if (isDotOpDispatch(ey))
- {
- unsigned errors = global.startGagging();
- e = expressionSemantic(ce->syntaxCopy(), sc);
- if (!global.endGagging(errors))
- return e;
- /* fall down to UFCS */
- }
- else
- return NULL;
- }
- }
- e = searchUFCS(sc, die, ident);
- }
- else if (ce->e1->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
- if (Expression *ey = semanticY(dti, sc, 1))
- {
- ce->e1 = ey;
- return NULL;
- }
- eleft = dti->e1;
- e = searchUFCS(sc, dti, dti->ti->name);
- }
- else
- return NULL;
-
- // Rewrite
- ce->e1 = e;
- if (!ce->arguments)
- ce->arguments = new Expressions();
- ce->arguments->shift(eleft);
-
- return NULL;
-}
-
-/******************************
- * Pull out property with UFCS.
- */
-
-static Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
-{
- Loc loc = e1->loc;
- Expression *eleft;
- Expression *e;
-
- if (e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)e1;
- eleft = die->e1;
- e = searchUFCS(sc, die, die->ident);
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti;
- dti = (DotTemplateInstanceExp *)e1;
- eleft = dti->e1;
- e = searchUFCS(sc, dti, dti->ti->name);
- }
- else
- return NULL;
-
- if (e == NULL)
- return NULL;
-
- // Rewrite
- if (e2)
- {
- // run semantic without gagging
- e2 = expressionSemantic(e2, sc);
-
- /* f(e1) = e2
- */
- Expression *ex = e->copy();
- Expressions *a1 = new Expressions();
- a1->setDim(1);
- (*a1)[0] = eleft;
- ex = new CallExp(loc, ex, a1);
- ex = trySemantic(ex, sc);
-
- /* f(e1, e2)
- */
- Expressions *a2 = new Expressions();
- a2->setDim(2);
- (*a2)[0] = eleft;
- (*a2)[1] = e2;
- e = new CallExp(loc, e, a2);
- if (ex)
- { // if fallback setter exists, gag errors
- e = trySemantic(e, sc);
- if (!e)
- { checkPropertyCall(ex);
- ex = new AssignExp(loc, ex, e2);
- return expressionSemantic(ex, sc);
- }
- }
- else
- { // strict setter prints errors if fails
- e = expressionSemantic(e, sc);
- }
- checkPropertyCall(e);
- return e;
- }
- else
- {
- /* f(e1)
- */
- Expressions *arguments = new Expressions();
- arguments->setDim(1);
- (*arguments)[0] = eleft;
- e = new CallExp(loc, e, arguments);
- e = expressionSemantic(e, sc);
- checkPropertyCall(e);
- return expressionSemantic(e, sc);
- }
-}
-
-/******************************
- * If e1 is a property function (template), resolve it.
- */
-
-Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
-{
- //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
- OverloadSet *os;
- FuncDeclaration *fd;
- TemplateDeclaration *td;
-
- if (e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)e1;
- if (de->e2->op == TOKoverloadset)
- {
- os = ((OverExp *)de->e2)->vars;
- goto Los;
- }
- }
- else if (e1->op == TOKoverloadset)
- {
- os = ((OverExp *)e1)->vars;
- Los:
- assert(os);
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s = os->a[i];
- fd = s->isFuncDeclaration();
- td = s->isTemplateDeclaration();
- if (fd)
- {
- if (((TypeFunction *)fd->type)->isproperty)
- return resolveProperties(sc, e1);
- }
- else if (td && td->onemember &&
- (fd = td->onemember->isFuncDeclaration()) != NULL)
- {
- if (((TypeFunction *)fd->type)->isproperty ||
- (fd->storage_class2 & STCproperty) ||
- (td->_scope->stc & STCproperty))
- {
- return resolveProperties(sc, e1);
- }
- }
- }
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
- if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
- goto Ltd;
- }
- else if (e1->op == TOKdottd)
- {
- td = ((DotTemplateExp *)e1)->td;
- goto Ltd;
- }
- else if (e1->op == TOKscope)
- {
- Dsymbol *s = ((ScopeExp *)e1)->sds;
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && !ti->semanticRun && ti->tempdecl)
- {
- if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
- goto Ltd;
- }
- }
- else if (e1->op == TOKtemplate)
- {
- td = ((TemplateExp *)e1)->td;
- Ltd:
- assert(td);
- if (td->onemember &&
- (fd = td->onemember->isFuncDeclaration()) != NULL)
- {
- if (((TypeFunction *)fd->type)->isproperty ||
- (fd->storage_class2 & STCproperty) ||
- (td->_scope->stc & STCproperty))
- {
- return resolveProperties(sc, e1);
- }
- }
- }
- else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e1;
- fd = dve->var->isFuncDeclaration();
- goto Lfd;
- }
- else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
- (sc->intypeof || !((VarExp *)e1)->var->needThis()))
- {
- fd = ((VarExp *)e1)->var->isFuncDeclaration();
- Lfd:
- assert(fd);
- if (((TypeFunction *)fd->type)->isproperty)
- return resolveProperties(sc, e1);
- }
- return e1;
-}
-
-/*************************************************************
- * Given var, we need to get the
- * right 'this' pointer if var is in an outer class, but our
- * existing 'this' pointer is in an inner class.
- * Input:
- * e1 existing 'this'
- * ad struct or class we need the correct 'this' for
- * var the specific member of ad we're accessing
- */
-
-static Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
- Expression *e1, Declaration *var, int flag = 0)
-{
- //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
- L1:
- Type *t = e1->type->toBasetype();
- //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
-
- /* If e1 is not the 'this' pointer for ad
- */
- if (ad &&
- !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
- ((TypeStruct *)t->nextOf())->sym == ad)
- &&
- !(t->ty == Tstruct &&
- ((TypeStruct *)t)->sym == ad)
- )
- {
- ClassDeclaration *cd = ad->isClassDeclaration();
- ClassDeclaration *tcd = t->isClassHandle();
-
- /* e1 is the right this if ad is a base class of e1
- */
- if (!cd || !tcd ||
- !(tcd == cd || cd->isBaseOf(tcd, NULL))
- )
- {
- /* Only classes can be inner classes with an 'outer'
- * member pointing to the enclosing class instance
- */
- if (tcd && tcd->isNested())
- {
- /* e1 is the 'this' pointer for an inner class: tcd.
- * Rewrite it as the 'this' pointer for the outer class.
- */
-
- e1 = new DotVarExp(loc, e1, tcd->vthis);
- e1->type = tcd->vthis->type;
- e1->type = e1->type->addMod(t->mod);
- // Do not call checkNestedRef()
- //e1 = expressionSemantic(e1, sc);
-
- // Skip up over nested functions, and get the enclosing
- // class type.
- int n = 0;
- Dsymbol *s;
- for (s = tcd->toParent();
- s && s->isFuncDeclaration();
- s = s->toParent())
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f->vthis)
- {
- //printf("rewriting e1 to %s's this\n", f->toChars());
- n++;
- e1 = new VarExp(loc, f->vthis);
- }
- else
- {
- e1->error("need `this` of type %s to access member %s"
- " from static function %s",
- ad->toChars(), var->toChars(), f->toChars());
- e1 = new ErrorExp();
- return e1;
- }
- }
- if (s && s->isClassDeclaration())
- {
- e1->type = s->isClassDeclaration()->type;
- e1->type = e1->type->addMod(t->mod);
- if (n > 1)
- e1 = expressionSemantic(e1, sc);
- }
- else
- e1 = expressionSemantic(e1, sc);
- goto L1;
- }
-
- /* Can't find a path from e1 to ad
- */
- if (flag)
- return NULL;
- e1->error("this for %s needs to be type %s not type %s",
- var->toChars(), ad->toChars(), t->toChars());
- return new ErrorExp();
- }
- }
- return e1;
-}
-
-/***************************************
- * Pull out any properties.
- */
-
-static Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
-{
- //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
- Loc loc = e1->loc;
-
- OverloadSet *os;
- Dsymbol *s;
- Objects *tiargs;
- Type *tthis;
- if (e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)e1;
- if (de->e2->op == TOKoverloadset)
- {
- tiargs = NULL;
- tthis = de->e1->type;
- os = ((OverExp *)de->e2)->vars;
- goto Los;
- }
- }
- else if (e1->op == TOKoverloadset)
- {
- tiargs = NULL;
- tthis = NULL;
- os = ((OverExp *)e1)->vars;
- Los:
- assert(os);
- FuncDeclaration *fd = NULL;
- if (e2)
- {
- e2 = expressionSemantic(e2, sc);
- if (e2->op == TOKerror)
- return new ErrorExp();
- e2 = resolveProperties(sc, e2);
-
- Expressions a;
- a.push(e2);
-
- for (size_t i = 0; i < os->a.length; i++)
- {
- FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
- if (f)
- {
- if (f->errors)
- return new ErrorExp();
- fd = f;
- assert(fd->type->ty == Tfunction);
- }
- }
- if (fd)
- {
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- }
- {
- for (size_t i = 0; i < os->a.length; i++)
- {
- FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
- if (f)
- {
- if (f->errors)
- return new ErrorExp();
- fd = f;
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (!tf->isref && e2)
- goto Leproplvalue;
- }
- }
- if (fd)
- {
- Expression *e = new CallExp(loc, e1);
- if (e2)
- e = new AssignExp(loc, e, e2);
- return expressionSemantic(e, sc);
- }
- }
- if (e2)
- goto Leprop;
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
- if (!dti->findTempDecl(sc))
- goto Leprop;
- if (!dti->ti->semanticTiargs(sc))
- goto Leprop;
- tiargs = dti->ti->tiargs;
- tthis = dti->e1->type;
- if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
- goto Los;
- if ((s = dti->ti->tempdecl) != NULL)
- goto Lfd;
- }
- else if (e1->op == TOKdottd)
- {
- DotTemplateExp *dte = (DotTemplateExp *)e1;
- s = dte->td;
- tiargs = NULL;
- tthis = dte->e1->type;
- goto Lfd;
- }
- else if (e1->op == TOKscope)
- {
- s = ((ScopeExp *)e1)->sds;
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && !ti->semanticRun && ti->tempdecl)
- {
- //assert(ti->needsTypeInference(sc));
- if (!ti->semanticTiargs(sc))
- goto Leprop;
- tiargs = ti->tiargs;
- tthis = NULL;
- if ((os = ti->tempdecl->isOverloadSet()) != NULL)
- goto Los;
- if ((s = ti->tempdecl) != NULL)
- goto Lfd;
- }
- }
- else if (e1->op == TOKtemplate)
- {
- s = ((TemplateExp *)e1)->td;
- tiargs = NULL;
- tthis = NULL;
- goto Lfd;
- }
- else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e1;
- s = dve->var->isFuncDeclaration();
- tiargs = NULL;
- tthis = dve->e1->type;
- goto Lfd;
- }
- else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
- {
- s = ((VarExp *)e1)->var->isFuncDeclaration();
- tiargs = NULL;
- tthis = NULL;
- Lfd:
- assert(s);
- if (e2)
- {
- e2 = expressionSemantic(e2, sc);
- if (e2->op == TOKerror)
- return new ErrorExp();
- e2 = resolveProperties(sc, e2);
-
- Expressions a;
- a.push(e2);
-
- FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
- if (fd && fd->type)
- {
- if (fd->errors)
- return new ErrorExp();
- assert(fd->type->ty == Tfunction);
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- }
- {
- FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
- if (fd && fd->type)
- {
- if (fd->errors)
- return new ErrorExp();
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (!e2 || tf->isref)
- {
- Expression *e = new CallExp(loc, e1);
- if (e2)
- e = new AssignExp(loc, e, e2);
- return expressionSemantic(e, sc);
- }
- }
- }
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- // Keep better diagnostic message for invalid property usage of functions
- assert(fd->type->ty == Tfunction);
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- if (e2)
- goto Leprop;
- }
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && ve->checkPurity(sc, v))
- return new ErrorExp();
- }
- if (e2)
- return NULL;
-
- if (e1->type &&
- e1->op != TOKtype) // function type is not a property
- {
- /* Look for e1 being a lazy parameter; rewrite as delegate call
- */
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
-
- if (ve->var->storage_class & STClazy)
- {
- Expression *e = new CallExp(loc, e1);
- return expressionSemantic(e, sc);
- }
- }
- else if (e1->op == TOKdotvar)
- {
- // Check for reading overlapped pointer field in @safe code.
- if (checkUnsafeAccess(sc, e1, true, true))
- return new ErrorExp();
- }
- else if (e1->op == TOKcall)
- {
- CallExp *ce = (CallExp *)e1;
- // Check for reading overlapped pointer field in @safe code.
- if (checkUnsafeAccess(sc, ce->e1, true, true))
- return new ErrorExp();
- }
- }
-
- if (!e1->type)
- {
- error(loc, "cannot resolve type for %s", e1->toChars());
- e1 = new ErrorExp();
- }
- return e1;
-
-Leprop:
- error(loc, "not a property %s", e1->toChars());
- return new ErrorExp();
-
-Leproplvalue:
- error(loc, "%s is not an lvalue", e1->toChars());
- return new ErrorExp();
-}
-
-Expression *resolveProperties(Scope *sc, Expression *e)
-{
- //printf("resolveProperties(%s)\n", e->toChars());
-
- e = resolvePropertiesX(sc, e);
- if (e->checkRightThis(sc))
- return new ErrorExp();
- return e;
-}
-
-/****************************************
- * The common type is determined by applying ?: to each pair.
- * Output:
- * exps[] properties resolved, implicitly cast to common type, rewritten in place
- * *pt if pt is not NULL, set to the common type
- * Returns:
- * true a semantic error was detected
- */
-
-static bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
-{
- /* Still have a problem with:
- * ubyte[][] = [ cast(ubyte[])"hello", [1]];
- * which works if the array literal is initialized top down with the ubyte[][]
- * type, but fails with this function doing bottom up typing.
- */
- //printf("arrayExpressionToCommonType()\n");
- IntegerExp integerexp(0);
- CondExp condexp(Loc(), &integerexp, NULL, NULL);
-
- Type *t0 = NULL;
- Expression *e0 = NULL; // dead-store to prevent spurious warning
- size_t j0 = ~0; // dead-store to prevent spurious warning
- bool foundType = false;
-
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (!e)
- continue;
-
- e = resolveProperties(sc, e);
- if (!e->type)
- {
- e->error("%s has no value", e->toChars());
- t0 = Type::terror;
- continue;
- }
- if (e->op == TOKtype)
- {
- foundType = true; // do not break immediately, there might be more errors
- e->checkValue(); // report an error "type T has no value"
- t0 = Type::terror;
- continue;
- }
- if (e->type->ty == Tvoid)
- {
- // void expressions do not concur to the determination of the common
- // type.
- continue;
- }
- if (checkNonAssignmentArrayOp(e))
- {
- t0 = Type::terror;
- continue;
- }
-
- e = doCopyOrMove(sc, e);
-
- if (!foundType && t0 && !t0->equals(e->type))
- {
- /* This applies ?: to merge the types. It's backwards;
- * ?: should call this function to merge types.
- */
- condexp.type = NULL;
- condexp.e1 = e0;
- condexp.e2 = e;
- condexp.loc = e->loc;
- Expression *ex = expressionSemantic(&condexp, sc);
- if (ex->op == TOKerror)
- e = ex;
- else
- {
- (*exps)[j0] = condexp.e1;
- e = condexp.e2;
- }
- }
- j0 = i;
- e0 = e;
- t0 = e->type;
- if (e->op != TOKerror)
- (*exps)[i] = e;
- }
-
- if (!t0)
- t0 = Type::tvoid; // [] is typed as void[]
- else if (t0->ty != Terror)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (!e)
- continue;
-
- e = e->implicitCastTo(sc, t0);
- //assert(e->op != TOKerror);
- if (e->op == TOKerror)
- {
- /* Bugzilla 13024: a workaround for the bug in typeMerge -
- * it should paint e1 and e2 by deduced common type,
- * but doesn't in this particular case.
- */
- t0 = Type::terror;
- break;
- }
- (*exps)[i] = e;
- }
- }
- if (pt)
- *pt = t0;
-
- return (t0 == Type::terror);
-}
-
-static Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
-{ Expression *e;
-
- switch (op)
- {
- case TOKaddass: e = new AddExp(loc, e1, e2); break;
- case TOKminass: e = new MinExp(loc, e1, e2); break;
- case TOKmulass: e = new MulExp(loc, e1, e2); break;
- case TOKdivass: e = new DivExp(loc, e1, e2); break;
- case TOKmodass: e = new ModExp(loc, e1, e2); break;
- case TOKandass: e = new AndExp(loc, e1, e2); break;
- case TOKorass: e = new OrExp (loc, e1, e2); break;
- case TOKxorass: e = new XorExp(loc, e1, e2); break;
- case TOKshlass: e = new ShlExp(loc, e1, e2); break;
- case TOKshrass: e = new ShrExp(loc, e1, e2); break;
- case TOKushrass: e = new UshrExp(loc, e1, e2); break;
- default: assert(0);
- }
- return e;
-}
-
-/*********************
- * Rewrite:
- * array.length op= e2
- * as:
- * array.length = array.length op e2
- * or:
- * auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
- */
-
-static Expression *rewriteOpAssign(BinExp *exp)
-{
- Expression *e;
-
- assert(exp->e1->op == TOKarraylength);
- ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
- if (ale->e1->op == TOKvar)
- {
- e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
- e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
- }
- else
- {
- /* auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
- */
- VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
-
- Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
- Expression *elvalue = e1->syntaxCopy();
- e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
- e = new AssignExp(exp->loc, elvalue, e);
- e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
- }
- return e;
-}
-
-/****************************************
- * Preprocess arguments to function.
- * Output:
- * exps[] tuples expanded, properties resolved, rewritten in place
- * Returns:
- * true a semantic error occurred
- */
-
-static bool preFunctionParameters(Scope *sc, Expressions *exps)
-{
- bool err = false;
- if (exps)
- {
- expandTuples(exps);
-
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *arg = (*exps)[i];
-
- arg = resolveProperties(sc, arg);
- if (arg->op == TOKtype)
- {
- arg->error("cannot pass type %s as a function argument", arg->toChars());
- arg = new ErrorExp();
- err = true;
- }
- else if (arg->type->toBasetype()->ty == Tfunction)
- {
- arg->error("cannot pass type %s as a function argument", arg->toChars());
- arg = new ErrorExp();
- err = true;
- }
- else if (checkNonAssignmentArrayOp(arg))
- {
- arg = new ErrorExp();
- err = true;
- }
- (*exps)[i] = arg;
- }
- }
- return err;
-}
-
-/********************************************
- * Issue an error if default construction is disabled for type t.
- * Default construction is required for arrays and 'out' parameters.
- * Returns:
- * true an error was issued
- */
-static bool checkDefCtor(Loc loc, Type *t)
-{
- t = t->baseElemOf();
- if (t->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)t)->sym;
- if (sd->noDefaultCtor)
- {
- sd->error(loc, "default construction is disabled");
- return true;
- }
- }
- return false;
-}
-
-/****************************************
- * Now that we know the exact type of the function we're calling,
- * the arguments[] need to be adjusted:
- * 1. implicitly convert argument to the corresponding parameter type
- * 2. add default arguments for any missing arguments
- * 3. do default promotions on arguments corresponding to ...
- * 4. add hidden _arguments[] argument
- * 5. call copy constructor for struct value arguments
- * Input:
- * tf type of the function
- * fd the function being called, NULL if called indirectly
- * Output:
- * *prettype return type of function
- * *peprefix expression to execute before arguments[] are evaluated, NULL if none
- * Returns:
- * true errors happened
- */
-
-static bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
- Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
-{
- //printf("functionParameters()\n");
- assert(arguments);
- assert(fd || tf->next);
- size_t nargs = arguments ? arguments->length : 0;
- size_t nparams = tf->parameterList.length();
- unsigned olderrors = global.errors;
- bool err = false;
- *prettype = Type::terror;
- Expression *eprefix = NULL;
- *peprefix = NULL;
-
- if (nargs > nparams && tf->parameterList.varargs == VARARGnone)
- {
- error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
- return true;
- }
-
- // If inferring return type, and semantic3() needs to be run if not already run
- if (!tf->next && fd->inferRetType)
- {
- fd->functionSemantic();
- }
- else if (fd && fd->parent)
- {
- TemplateInstance *ti = fd->parent->isTemplateInstance();
- if (ti && ti->tempdecl)
- {
- fd->functionSemantic3();
- }
- }
- bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
-
- size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
-
- /* If the function return type has wildcards in it, we'll need to figure out the actual type
- * based on the actual argument types.
- */
- MOD wildmatch = 0;
- if (tthis && tf->isWild() && !isCtorCall)
- {
- Type *t = tthis;
- if (t->isImmutable())
- wildmatch = MODimmutable;
- else if (t->isWildConst())
- wildmatch = MODwildconst;
- else if (t->isWild())
- wildmatch = MODwild;
- else if (t->isConst())
- wildmatch = MODconst;
- else
- wildmatch = MODmutable;
- }
-
- int done = 0;
- for (size_t i = 0; i < n; i++)
- {
- Expression *arg;
-
- if (i < nargs)
- arg = (*arguments)[i];
- else
- arg = NULL;
-
- if (i < nparams)
- {
- Parameter *p = tf->parameterList[i];
-
- if (!arg)
- {
- if (!p->defaultArg)
- {
- if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- goto L2;
- error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
- return true;
- }
- arg = p->defaultArg;
- arg = inlineCopy(arg, sc);
- // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
- arg = arg->resolveLoc(loc, sc);
- arguments->push(arg);
- nargs++;
- }
-
- if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- {
- //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
- {
- MATCH m;
- if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
- {
- if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
- goto L2;
- else if (nargs != nparams)
- { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
- return true;
- }
- goto L1;
- }
- }
- L2:
- Type *tb = p->type->toBasetype();
- Type *tret = p->isLazyArray();
- switch (tb->ty)
- {
- case Tsarray:
- case Tarray:
- {
- /* Create a static array variable v of type arg->type:
- * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
- *
- * The array literal in the initializer of the hidden variable
- * is now optimized. See Bugzilla 2356.
- */
- Type *tbn = ((TypeArray *)tb)->next;
-
- Expressions *elements = new Expressions();
- elements->setDim(nargs - i);
- for (size_t u = 0; u < elements->length; u++)
- {
- Expression *a = (*arguments)[i + u];
- if (tret && a->implicitConvTo(tret))
- {
- a = a->implicitCastTo(sc, tret);
- a = a->optimize(WANTvalue);
- a = toDelegate(a, a->type, sc);
- }
- else
- a = a->implicitCastTo(sc, tbn);
- (*elements)[u] = a;
- }
- // Bugzilla 14395: Convert to a static array literal, or its slice.
- arg = new ArrayLiteralExp(loc, tbn->sarrayOf(nargs - i), elements);
- if (tb->ty == Tarray)
- {
- arg = new SliceExp(loc, arg, NULL, NULL);
- arg->type = p->type;
- }
- break;
- }
- case Tclass:
- {
- /* Set arg to be:
- * new Tclass(arg0, arg1, ..., argn)
- */
- Expressions *args = new Expressions();
- args->setDim(nargs - i);
- for (size_t u = i; u < nargs; u++)
- (*args)[u - i] = (*arguments)[u];
- arg = new NewExp(loc, NULL, NULL, p->type, args);
- break;
- }
- default:
- if (!arg)
- {
- error(loc, "not enough arguments");
- return true;
- }
- break;
- }
- arg = expressionSemantic(arg, sc);
- //printf("\targ = '%s'\n", arg->toChars());
- arguments->setDim(i + 1);
- (*arguments)[i] = arg;
- nargs = i + 1;
- done = 1;
- }
-
- L1:
- if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
- {
- bool isRef = (p->storageClass & (STCref | STCout)) != 0;
- if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
- {
- if (wildmatch)
- wildmatch = MODmerge(wildmatch, wm);
- else
- wildmatch = wm;
- //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
- }
- }
- }
- if (done)
- break;
- }
- if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
- tf->next->hasWild() &&
- (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
- {
- if (fd)
- {
- /* If the called function may return the reference to
- * outer inout data, it should be rejected.
- *
- * void foo(ref inout(int) x) {
- * ref inout(int) bar(inout(int)) { return x; }
- * struct S { ref inout(int) bar() inout { return x; } }
- * bar(int.init) = 1; // bad!
- * S().bar() = 1; // bad!
- * }
- */
- Dsymbol *s = NULL;
- if (fd->isThis() || fd->isNested())
- s = fd->toParent2();
- for (; s; s = s->toParent2())
- {
- if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (ad->isNested())
- continue;
- break;
- }
- if (FuncDeclaration *ff = s->isFuncDeclaration())
- {
- if (((TypeFunction *)ff->type)->iswild)
- goto Linouterr;
-
- if (ff->isNested() || ff->isThis())
- continue;
- }
- break;
- }
- }
- else if (tf->isWild())
- {
- Linouterr:
- const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
- error(loc, "modify inout to %s is not allowed inside inout function", s);
- return true;
- }
- }
-
- assert(nargs >= nparams);
- for (size_t i = 0; i < nargs; i++)
- {
- Expression *arg = (*arguments)[i];
- assert(arg);
- if (i < nparams)
- {
- Parameter *p = tf->parameterList[i];
-
- if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
- {
- Type *tprm = p->type;
- if (p->type->hasWild())
- tprm = p->type->substWildTo(wildmatch);
- if (!tprm->equals(arg->type))
- {
- //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
- arg = arg->implicitCastTo(sc, tprm);
- arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
- }
- }
- if (p->storageClass & STCref)
- {
- arg = arg->toLvalue(sc, arg);
-
- // Look for mutable misaligned pointer, etc., in @safe mode
- err |= checkUnsafeAccess(sc, arg, false, true);
- }
- else if (p->storageClass & STCout)
- {
- Type *t = arg->type;
- if (!t->isMutable() || !t->isAssignable()) // check blit assignable
- {
- arg->error("cannot modify struct %s with immutable members", arg->toChars());
- err = true;
- }
- else
- {
- // Look for misaligned pointer, etc., in @safe mode
- err |= checkUnsafeAccess(sc, arg, false, true);
- err |= checkDefCtor(arg->loc, t); // t must be default constructible
- }
- arg = arg->toLvalue(sc, arg);
- }
- else if (p->storageClass & STClazy)
- {
- // Convert lazy argument to a delegate
- if (p->type->ty == Tvoid)
- arg = toDelegate(arg, p->type, sc);
- else
- arg = toDelegate(arg, arg->type, sc);
- }
-
- //printf("arg: %s\n", arg->toChars());
- //printf("type: %s\n", arg->type->toChars());
- if (tf->parameterEscapes(p))
- {
- /* Argument value can escape from the called function.
- * Check arg to see if it matters.
- */
- if (global.params.vsafe)
- err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
- }
- else
- {
- /* Argument value cannot escape from the called function.
- */
- Expression *a = arg;
- if (a->op == TOKcast)
- a = ((CastExp *)a)->e1;
-
- if (a->op == TOKfunction)
- {
- /* Function literals can only appear once, so if this
- * appearance was scoped, there cannot be any others.
- */
- FuncExp *fe = (FuncExp *)a;
- fe->fd->tookAddressOf = 0;
- }
- else if (a->op == TOKdelegate)
- {
- /* For passing a delegate to a scoped parameter,
- * this doesn't count as taking the address of it.
- * We only worry about 'escaping' references to the function.
- */
- DelegateExp *de = (DelegateExp *)a;
- if (de->e1->op == TOKvar)
- { VarExp *ve = (VarExp *)de->e1;
- FuncDeclaration *f = ve->var->isFuncDeclaration();
- if (f)
- { f->tookAddressOf--;
- //printf("tookAddressOf = %d\n", f->tookAddressOf);
- }
- }
- }
- }
- arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
- }
- else
- {
- // These will be the trailing ... arguments
-
- // If not D linkage, do promotions
- if (tf->linkage != LINKd)
- {
- // Promote bytes, words, etc., to ints
- arg = integralPromotions(arg, sc);
-
- // Promote floats to doubles
- switch (arg->type->ty)
- {
- case Tfloat32:
- arg = arg->castTo(sc, Type::tfloat64);
- break;
-
- case Timaginary32:
- arg = arg->castTo(sc, Type::timaginary64);
- break;
- }
-
- if (tf->parameterList.varargs == VARARGvariadic)
- {
- const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
- if (arg->type->ty == Tarray)
- {
- arg->error("cannot pass dynamic arrays to %s vararg functions", p);
- err = true;
- }
- if (arg->type->ty == Tsarray)
- {
- arg->error("cannot pass static arrays to %s vararg functions", p);
- err = true;
- }
- }
- }
-
- // Do not allow types that need destructors
- if (arg->type->needsDestruction())
- {
- arg->error("cannot pass types that need destruction as variadic arguments");
- err = true;
- }
-
- // Convert static arrays to dynamic arrays
- // BUG: I don't think this is right for D2
- Type *tb = arg->type->toBasetype();
- if (tb->ty == Tsarray)
- {
- TypeSArray *ts = (TypeSArray *)tb;
- Type *ta = ts->next->arrayOf();
- if (ts->size(arg->loc) == 0)
- arg = new NullExp(arg->loc, ta);
- else
- arg = arg->castTo(sc, ta);
- }
- if (tb->ty == Tstruct)
- {
- //arg = callCpCtor(sc, arg);
- }
-
- // Give error for overloaded function addresses
- if (arg->op == TOKsymoff)
- { SymOffExp *se = (SymOffExp *)arg;
- if (se->hasOverloads &&
- !se->var->isFuncDeclaration()->isUnique())
- { arg->error("function %s is overloaded", arg->toChars());
- err = true;
- }
- }
- if (arg->checkValue())
- err = true;
- arg = arg->optimize(WANTvalue);
- }
- (*arguments)[i] = arg;
- }
-
- /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
- */
- const bool isVa_list = tf->parameterList.varargs == VARARGnone;
- if (fd && (fd->flags & FUNCFLAGprintf))
- {
- if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
- {
- Expressions argslice;
- argslice.reserve(nargs - nparams);
- for (size_t i = nparams; i < nargs; i++)
- argslice.push((*arguments)[i]);
- checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
- }
- }
- else if (fd && (fd->flags & FUNCFLAGscanf))
- {
- if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
- {
- Expressions argslice;
- argslice.reserve(nargs - nparams);
- for (size_t i = nparams; i < nargs; i++)
- argslice.push((*arguments)[i]);
- checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
- }
- }
-
- /* Remaining problems:
- * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
- * implemented by calling a function) we'll defer this for now.
- * 2. value structs (or static arrays of them) that need to be copy constructed
- * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
- * function gets called (functions normally destroy their parameters)
- * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
- * up properly. Pushing arguments on the stack then cannot fail.
- */
- if (1)
- {
- /* TODO: tackle problem 1)
- */
- const bool leftToRight = true; // TODO: something like !fd.isArrayOp
- if (!leftToRight)
- assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
-
- const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
- const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
- const ptrdiff_t step = (leftToRight ? 1 : -1);
-
- /* Compute indices of last throwing argument and first arg needing destruction.
- * Used to not set up destructors unless an arg needs destruction on a throw
- * in a later argument.
- */
- ptrdiff_t lastthrow = -1;
- ptrdiff_t firstdtor = -1;
- for (ptrdiff_t i = start; i != end; i += step)
- {
- Expression *arg = (*arguments)[i];
- if (canThrow(arg, sc->func, false))
- lastthrow = i;
- if (firstdtor == -1 && arg->type->needsDestruction())
- {
- Parameter *p = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
- if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
- firstdtor = i;
- }
- }
-
- /* Does problem 3) apply to this call?
- */
- const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
- && (lastthrow - firstdtor) * step > 0);
-
- /* If so, initialize 'eprefix' by declaring the gate
- */
- VarDeclaration *gate = NULL;
- if (needsPrefix)
- {
- // eprefix => bool __gate [= false]
- Identifier *idtmp = Identifier::generateId("__gate");
- gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
- gate->storage_class |= STCtemp | STCctfe | STCvolatile;
- dsymbolSemantic(gate, sc);
-
- Expression *ae = new DeclarationExp(loc, gate);
- eprefix = expressionSemantic(ae, sc);
- }
-
- for (ptrdiff_t i = start; i != end; i += step)
- {
- Expression *arg = (*arguments)[i];
-
- Parameter *parameter = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
- const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
- const bool isLazy = (parameter && (parameter->storageClass & STClazy));
-
- /* Skip lazy parameters
- */
- if (isLazy)
- continue;
-
- /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
- * Declare a temporary variable for this arg and append that declaration to 'eprefix',
- * which will implicitly take care of potential problem 2) for this arg.
- * 'eprefix' will therefore finally contain all args up to and including the last
- * potentially throwing arg, excluding all lazy parameters.
- */
- if (gate)
- {
- const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
-
- /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
- */
- VarDeclaration *tmp = copyToTemp(0,
- needsDtor ? "__pfx" : "__pfy",
- !isRef ? arg : arg->addressOf());
- dsymbolSemantic(tmp, sc);
-
- /* Modify the destructor so it only runs if gate==false, i.e.,
- * only if there was a throw while constructing the args
- */
- if (!needsDtor)
- {
- if (tmp->edtor)
- {
- assert(i == lastthrow);
- tmp->edtor = NULL;
- }
- }
- else
- {
- // edtor => (__gate || edtor)
- assert(tmp->edtor);
- Expression *e = tmp->edtor;
- e = new LogicalExp(e->loc, TOKoror, new VarExp(e->loc, gate), e);
- tmp->edtor = expressionSemantic(e, sc);
- //printf("edtor: %s\n", tmp->edtor->toChars());
- }
-
- // eprefix => (eprefix, auto __pfx/y = arg)
- DeclarationExp *ae = new DeclarationExp(loc, tmp);
- eprefix = Expression::combine(eprefix, expressionSemantic(ae, sc));
-
- // arg => __pfx/y
- arg = new VarExp(loc, tmp);
- arg = expressionSemantic(arg, sc);
- if (isRef)
- {
- arg = new PtrExp(loc, arg);
- arg = expressionSemantic(arg, sc);
- }
-
- /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
- * i.e., disable the dtors right after constructing the last throwing arg.
- * From now on, the callee will take care of destructing the args because
- * the args are implicitly moved into function parameters.
- *
- * Set gate to null to let the next iterations know they don't need to
- * append to eprefix anymore.
- */
- if (i == lastthrow)
- {
- Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
- eprefix = Expression::combine(eprefix, expressionSemantic(e, sc));
- gate = NULL;
- }
- }
- else
- {
- /* No gate, no prefix to append to.
- * Handle problem 2) by calling the copy constructor for value structs
- * (or static arrays of them) if appropriate.
- */
- Type *tv = arg->type->baseElemOf();
- if (!isRef && tv->ty == Tstruct)
- arg = doCopyOrMove(sc, arg);
- }
-
- (*arguments)[i] = arg;
- }
- }
- //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
-
- // If D linkage and variadic, add _arguments[] as first argument
- if (tf->isDstyleVariadic())
- {
- assert(arguments->length >= nparams);
-
- Parameters *args = new Parameters;
- args->setDim(arguments->length - nparams);
- for (size_t i = 0; i < arguments->length - nparams; i++)
- {
- Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL);
- (*args)[i] = arg;
- }
-
- TypeTuple *tup = new TypeTuple(args);
- Expression *e = new TypeidExp(loc, tup);
- e = expressionSemantic(e, sc);
- arguments->insert(0, e);
- }
-
- Type *tret = tf->next;
- if (isCtorCall)
- {
- //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
- // wildmatch, tf->isWild(), fd->isolateReturn());
- if (!tthis)
- {
- assert(sc->intypeof || global.errors);
- tthis = fd->isThis()->type->addMod(fd->type->mod);
- }
- if (tf->isWild() && !fd->isolateReturn())
- {
- if (wildmatch)
- tret = tret->substWildTo(wildmatch);
- int offset;
- if (!tret->implicitConvTo(tthis) &&
- !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
- {
- const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
- const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
- ::error(loc, "inout constructor %s creates%s object, not%s",
- fd->toPrettyChars(), s1, s2);
- err = true;
- }
- }
- tret = tthis;
- }
- else if (wildmatch && tret)
- {
- /* Adjust function return type based on wildmatch
- */
- //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
- tret = tret->substWildTo(wildmatch);
- }
- *prettype = tret;
- *peprefix = eprefix;
- return (err || olderrors != global.errors);
-}
-
-/**
- * Determines whether a symbol represents a module or package
- * (Used as a helper for is(type == module) and is(type == package))
- *
- * Params:
- * sym = the symbol to be checked
- *
- * Returns:
- * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
- */
-Package *resolveIsPackage(Dsymbol *sym)
-{
- Package *pkg;
- if (Import *imp = sym->isImport())
- {
- if (imp->pkg == NULL)
- {
- error(sym->loc, "Internal Compiler Error: unable to process forward-referenced import `%s`",
- imp->toChars());
- assert(0);
- }
- pkg = imp->pkg;
- }
- else if (Module *mod = sym->isModule())
- pkg = mod->isPackageFile ? mod->pkg : sym->isPackage();
- else
- pkg = sym->isPackage();
- if (pkg)
- pkg->resolvePKGunknown();
- return pkg;
-}
-
-static Module *loadStdMath()
-{
- static Import *impStdMath = NULL;
- if (!impStdMath)
- {
- Identifiers *a = new Identifiers();
- a->push(Id::std);
- Import *s = new Import(Loc(), a, Id::math, NULL, false);
- s->load(NULL);
- if (s->mod)
- {
- s->mod->importAll(NULL);
- dsymbolSemantic(s->mod, NULL);
- }
- impStdMath = s;
- }
- return impStdMath->mod;
-}
-
-class ExpressionSemanticVisitor : public Visitor
-{
-public:
- Expression *result;
- Scope *sc;
-
- ExpressionSemanticVisitor(Scope *sc)
- {
- this->result = NULL;
- this->sc = sc;
- }
-
-private:
- void setError()
- {
- result = new ErrorExp();
- }
-
- /*********************
- * Mark the operand as will never be dereferenced,
- * which is useful info for @safe checks.
- * Do before semantic() on operands rewrites them.
- */
- static void setNoderefOperand(UnaExp *e)
- {
- if (e->e1->op == TOKdotid)
- ((DotIdExp *)e->e1)->noderef = true;
- }
-
- /*********************
- * Mark the operands as will never be dereferenced,
- * which is useful info for @safe checks.
- * Do before semantic() on operands rewrites them.
- */
- static void setNoderefOperands(BinExp *e)
- {
- if (e->e1->op == TOKdotid)
- ((DotIdExp *)e->e1)->noderef = true;
- if (e->e2->op == TOKdotid)
- ((DotIdExp *)e->e2)->noderef = true;
- }
-
- static FuncDeclaration *resolveOverloadSet(Loc loc, Scope *sc,
- OverloadSet *os, Objects* tiargs, Type *tthis, Expressions *arguments)
- {
- FuncDeclaration *f = NULL;
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s = os->a[i];
- if (tiargs && s->isFuncDeclaration())
- continue;
- if (FuncDeclaration *f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, 1))
- {
- if (f2->errors)
- return NULL;
- if (f)
- {
- /* Error if match in more than one overload set,
- * even if one is a 'better' match than the other.
- */
- ScopeDsymbol::multiplyDefined(loc, f, f2);
- }
- else
- f = f2;
- }
- }
- if (!f)
- ::error(loc, "no overload matches for %s", os->toChars());
- else if (f->errors)
- f = NULL;
- return f;
- }
-
- /****************************************************
- * Determine if `exp`, which takes the address of `v`, can do so safely.
- * Params:
- * sc = context
- * exp = expression that takes the address of `v`
- * v = the variable getting its address taken
- * Returns:
- * `true` if ok, `false` for error
- */
- static bool checkAddressVar(Scope *sc, UnaExp *e, VarDeclaration *v)
- {
- if (v)
- {
- if (!v->canTakeAddressOf())
- {
- e->error("cannot take address of %s", e->e1->toChars());
- return false;
- }
- if (sc->func && !sc->intypeof && !v->isDataseg())
- {
- const char *p = v->isParameter() ? "parameter" : "local";
- if (global.params.vsafe)
- {
- // Taking the address of v means it cannot be set to 'scope' later
- v->storage_class &= ~STCmaybescope;
- v->doNotInferScope = true;
- if (v->storage_class & STCscope && sc->func->setUnsafe())
- {
- e->error("cannot take address of scope %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
- return false;
- }
- }
- else if (sc->func->setUnsafe())
- {
- e->error("cannot take address of %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
- return false;
- }
- }
- }
- return true;
- }
-
- static bool checkVectorElem(Expression *e, Expression *elem)
- {
- if (elem->isConst() == 1)
- return false;
-
- e->error("constant expression expected, not %s", elem->toChars());
- return true;
- }
-
-public:
- void visit(Expression *e)
- {
- if (e->type)
- e->type = typeSemantic(e->type, e->loc, sc);
- else
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(IntegerExp *e)
- {
- assert(e->type);
- if (e->type->ty == Terror)
- return setError();
- assert(e->type->deco);
- e->normalize();
- result = e;
- }
-
- void visit(RealExp *e)
- {
- if (!e->type)
- e->type = Type::tfloat64;
- else
- e->type = typeSemantic(e->type, e->loc, sc);
- result = e;
- }
-
- void visit(ComplexExp *e)
- {
- if (!e->type)
- e->type = Type::tcomplex80;
- else
- e->type = typeSemantic(e->type, e->loc, sc);
- result = e;
- }
-
- void visit(IdentifierExp *exp)
- {
- if (exp->type) // This is used as the dummy expression
- {
- result = exp;
- return;
- }
-
- Dsymbol *scopesym;
- Dsymbol *s = sc->search(exp->loc, exp->ident, &scopesym);
- if (s)
- {
- if (s->errors)
- return setError();
-
- Expression *e;
-
- /* See if the symbol was a member of an enclosing 'with'
- */
- WithScopeSymbol *withsym = scopesym->isWithScopeSymbol();
- if (withsym && withsym->withstate->wthis && symbolIsVisible(sc, s))
- {
- /* Disallow shadowing
- */
- // First find the scope of the with
- Scope *scwith = sc;
- while (scwith->scopesym != scopesym)
- {
- scwith = scwith->enclosing;
- assert(scwith);
- }
- // Look at enclosing scopes for symbols with the same name,
- // in the same function
- for (Scope *scx = scwith; scx && scx->func == scwith->func; scx = scx->enclosing)
- {
- Dsymbol *s2;
- if (scx->scopesym && scx->scopesym->symtab &&
- (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
- s != s2)
- {
- exp->error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars());
- return setError();
- }
- }
- s = s->toAlias();
-
- // Same as wthis.ident
- // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
- // The redudancy should be removed.
- e = new VarExp(exp->loc, withsym->withstate->wthis);
- e = new DotIdExp(exp->loc, e, exp->ident);
- e = expressionSemantic(e, sc);
- }
- else
- {
- if (withsym)
- {
- if (withsym->withstate->exp->type->ty != Tvoid)
- {
- // with (exp)' is a type expression
- // or 's' is not visible there (for error message)
- e = new TypeExp(exp->loc, withsym->withstate->exp->type);
- }
- else
- {
- // 'with (exp)' is a Package/Module
- e = withsym->withstate->exp;
- }
- e = new DotIdExp(exp->loc, e, exp->ident);
- result = expressionSemantic(e, sc);
- return;
- }
-
- /* If f is really a function template,
- * then replace f with the function template declaration.
- */
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- TemplateDeclaration *td = getFuncTemplateDecl(f);
- if (td)
- {
- if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
- td = td->overroot; // then get the start
- e = new TemplateExp(exp->loc, td, f);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- // Haven't done overload resolution yet, so pass 1
- e = resolve(exp->loc, sc, s, true);
- }
- result = e;
- return;
- }
-
- if (hasThis(sc))
- {
- AggregateDeclaration *ad = sc->getStructClassScope();
- if (ad && ad->aliasthis)
- {
- Expression *e;
- e = new IdentifierExp(exp->loc, Id::This);
- e = new DotIdExp(exp->loc, e, ad->aliasthis->ident);
- e = new DotIdExp(exp->loc, e, exp->ident);
- e = trySemantic(e, sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- }
-
- if (exp->ident == Id::ctfe)
- {
- if (sc->flags & SCOPEctfe)
- {
- exp->error("variable __ctfe cannot be read at compile time");
- return setError();
- }
-
- // Create the magic __ctfe bool variable
- VarDeclaration *vd = new VarDeclaration(exp->loc, Type::tbool, Id::ctfe, NULL);
- vd->storage_class |= STCtemp;
- vd->semanticRun = PASSsemanticdone;
- Expression *e = new VarExp(exp->loc, vd);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- // If we've reached this point and are inside a with() scope then we may
- // try one last attempt by checking whether the 'wthis' object supports
- // dynamic dispatching via opDispatch.
- // This is done by rewriting this expression as wthis.ident.
- for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing)
- {
- if (!sc2->scopesym)
- continue;
-
- if (WithScopeSymbol *ss = sc2->scopesym->isWithScopeSymbol())
- {
- if (ss->withstate->wthis)
- {
- Expression *e;
- e = new VarExp(exp->loc, ss->withstate->wthis);
- e = new DotIdExp(exp->loc, e, exp->ident);
- e = trySemantic(e, sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- break;
- }
- }
-
- /* Look for what user might have meant
- */
- if (const char *n = importHint(exp->ident->toChars()))
- exp->error("`%s` is not defined, perhaps `import %s;` is needed?", exp->ident->toChars(), n);
- else if (Dsymbol *s2 = sc->search_correct(exp->ident))
- exp->error("undefined identifier `%s`, did you mean %s `%s`?", exp->ident->toChars(), s2->kind(), s2->toChars());
- else if (const char *p = Scope::search_correct_C(exp->ident))
- exp->error("undefined identifier `%s`, did you mean `%s`?", exp->ident->toChars(), p);
- else
- exp->error("undefined identifier `%s`", exp->ident->toChars());
- return setError();
- }
-
- void visit(DsymbolExp *e)
- {
- result = resolve(e->loc, sc, e->s, e->hasOverloads);
- }
-
- void visit(ThisExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
-
- /* Special case for typeof(this) and typeof(super) since both
- * should work even if they are not inside a non-static member function
- */
- if (!fd && sc->intypeof == 1)
- {
- // Find enclosing struct or class
- for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent)
- {
- if (!s)
- {
- e->error("%s is not in a class or struct scope", e->toChars());
- goto Lerr;
- }
- ClassDeclaration *cd = s->isClassDeclaration();
- if (cd)
- {
- e->type = cd->type;
- result = e;
- return;
- }
- StructDeclaration *sd = s->isStructDeclaration();
- if (sd)
- {
- e->type = sd->type;
- result = e;
- return;
- }
- }
- }
- if (!fd)
- goto Lerr;
-
- assert(fd->vthis);
- e->var = fd->vthis;
- assert(e->var->parent);
- e->type = e->var->type;
- if (e->var->checkNestedReference(sc, e->loc))
- return setError();
- if (!sc->intypeof)
- sc->callSuper |= CSXthis;
- result = e;
- return;
-
- Lerr:
- e->error("`this` is only defined in non-static member functions, not %s", sc->parent->toChars());
- return setError();
- }
-
- void visit(SuperExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- FuncDeclaration *fd = hasThis(sc);
- ClassDeclaration *cd;
- Dsymbol *s;
-
- /* Special case for typeof(this) and typeof(super) since both
- * should work even if they are not inside a non-static member function
- */
- if (!fd && sc->intypeof == 1)
- {
- // Find enclosing class
- for (s = sc->getStructClassScope(); 1; s = s->parent)
- {
- if (!s)
- {
- e->error("%s is not in a class scope", e->toChars());
- goto Lerr;
- }
- cd = s->isClassDeclaration();
- if (cd)
- {
- cd = cd->baseClass;
- if (!cd)
- {
- e->error("class %s has no `super`", s->toChars());
- goto Lerr;
- }
- e->type = cd->type;
- result = e;
- return;
- }
- }
- }
- if (!fd)
- goto Lerr;
-
- e->var = fd->vthis;
- assert(e->var && e->var->parent);
-
- s = fd->toParent();
- while (s && s->isTemplateInstance())
- s = s->toParent();
- if (s->isTemplateDeclaration()) // allow inside template constraint
- s = s->toParent();
- assert(s);
- cd = s->isClassDeclaration();
- //printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars());
- if (!cd)
- goto Lerr;
- if (!cd->baseClass)
- {
- e->error("no base class for %s", cd->toChars());
- e->type = e->var->type;
- }
- else
- {
- e->type = cd->baseClass->type;
- e->type = e->type->castMod(e->var->type->mod);
- }
-
- if (e->var->checkNestedReference(sc, e->loc))
- return setError();
-
- if (!sc->intypeof)
- sc->callSuper |= CSXsuper;
- result = e;
- return;
-
- Lerr:
- e->error("`super` is only allowed in non-static class member functions");
- return setError();
- }
-
- void visit(NullExp *e)
- {
- // NULL is the same as (void *)0
- if (e->type)
- {
- result = e;
- return;
- }
- e->type = Type::tnull;
- result = e;
- }
-
- void visit(StringExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- OutBuffer buffer;
- size_t newlen = 0;
- const char *p;
- size_t u;
- unsigned c;
-
- switch (e->postfix)
- {
- case 'd':
- for (u = 0; u < e->len;)
- {
- p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
- if (p)
- {
- e->error("%s", p);
- return setError();
- }
- else
- {
- buffer.write4(c);
- newlen++;
- }
- }
- buffer.write4(0);
- e->string = buffer.extractData();
- e->len = newlen;
- e->sz = 4;
- e->type = new TypeDArray(Type::tdchar->immutableOf());
- e->committed = 1;
- break;
-
- case 'w':
- for (u = 0; u < e->len;)
- {
- p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
- if (p)
- {
- e->error("%s", p);
- return setError();
- }
- else
- {
- buffer.writeUTF16(c);
- newlen++;
- if (c >= 0x10000)
- newlen++;
- }
- }
- buffer.writeUTF16(0);
- e->string = buffer.extractData();
- e->len = newlen;
- e->sz = 2;
- e->type = new TypeDArray(Type::twchar->immutableOf());
- e->committed = 1;
- break;
-
- case 'c':
- e->committed = 1;
- /* fall through */
-
- default:
- e->type = new TypeDArray(Type::tchar->immutableOf());
- break;
- }
- e->type = typeSemantic(e->type, e->loc, sc);
- //e->type = e->type->immutableOf();
- //printf("type = %s\n", e->type->toChars());
-
- result = e;
- }
-
- void visit(ArrayLiteralExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- /* Perhaps an empty array literal [ ] should be rewritten as null?
- */
-
- if (e->basis)
- e->basis = expressionSemantic(e->basis, sc);
- if (arrayExpressionSemantic(e->elements, sc) || (e->basis && e->basis->op == TOKerror))
- return setError();
- expandTuples(e->elements);
-
- Type *t0;
- if (e->basis)
- e->elements->push(e->basis);
- bool err = arrayExpressionToCommonType(sc, e->elements, &t0);
- if (e->basis)
- e->elements->pop();
- if (err)
- return setError();
-
- e->type = t0->arrayOf();
- e->type = typeSemantic(e->type, e->loc, sc);
-
- /* Disallow array literals of type void being used.
- */
- if (e->elements->length > 0 && t0->ty == Tvoid)
- {
- e->error("%s of type %s has no value", e->toChars(), e->type->toChars());
- return setError();
- }
-
- if (global.params.useTypeInfo && Type::dtypeinfo)
- semanticTypeInfo(sc, e->type);
-
- result = e;
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- // Run semantic() on each element
- bool err_keys = arrayExpressionSemantic(e->keys, sc);
- bool err_vals = arrayExpressionSemantic(e->values, sc);
- if (err_keys || err_vals)
- return setError();
- expandTuples(e->keys);
- expandTuples(e->values);
- if (e->keys->length != e->values->length)
- {
- e->error("number of keys is %u, must match number of values %u", e->keys->length, e->values->length);
- return setError();
- }
-
- Type *tkey = NULL;
- Type *tvalue = NULL;
- err_keys = arrayExpressionToCommonType(sc, e->keys, &tkey);
- err_vals = arrayExpressionToCommonType(sc, e->values, &tvalue);
- if (err_keys || err_vals)
- return setError();
-
- if (tkey == Type::terror || tvalue == Type::terror)
- return setError();
-
- e->type = new TypeAArray(tvalue, tkey);
- e->type = typeSemantic(e->type, e->loc, sc);
-
- semanticTypeInfo(sc, e->type);
-
- result = e;
- }
-
- void visit(StructLiteralExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- e->sd->size(e->loc);
- if (e->sd->sizeok != SIZEOKdone)
- return setError();
-
- if (arrayExpressionSemantic(e->elements, sc)) // run semantic() on each element
- return setError();
- expandTuples(e->elements);
-
- /* Fit elements[] to the corresponding type of field[].
- */
- if (!e->sd->fit(e->loc, sc, e->elements, e->stype))
- return setError();
-
- /* Fill out remainder of elements[] with default initializers for fields[]
- */
- if (!e->sd->fill(e->loc, e->elements, false))
- {
- /* An error in the initializer needs to be recorded as an error
- * in the enclosing function or template, since the initializer
- * will be part of the stuct declaration.
- */
- global.increaseErrorCount();
- return setError();
- }
-
- if (checkFrameAccess(e->loc, sc, e->sd, e->elements->length))
- return setError();
-
- e->type = e->stype ? e->stype : e->sd->type;
- result = e;
- }
-
- void visit(TypeExp *exp)
- {
- if (exp->type->ty == Terror)
- return setError();
-
- //printf("TypeExp::semantic(%s)\n", exp->type->toChars());
- Expression *e;
- Type *t;
- Dsymbol *s;
-
- exp->type->resolve(exp->loc, sc, &e, &t, &s, true);
- if (e)
- {
- // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
- // then rewrite as `(this.var)` in case it would be followed by a DotVar
- // to fix https://issues.dlang.org/show_bug.cgi?id=9490
- VarExp *ve = e->isVarExp();
- if (ve && ve->var && exp->parens && !ve->var->isStatic() && !(sc->stc & STCstatic) &&
- sc->func && sc->func->needThis() && ve->var->toParent2()->isAggregateDeclaration())
- {
- // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e->toChars());
- e = new DotVarExp(exp->loc, new ThisExp(exp->loc), ve->var, false);
- }
- //printf("e = %s %s\n", Token::toChars(e->op), e->toChars());
- e = expressionSemantic(e, sc);
- }
- else if (t)
- {
- //printf("t = %d %s\n", t->ty, t->toChars());
- exp->type = typeSemantic(t, exp->loc, sc);
- e = exp;
- }
- else if (s)
- {
- //printf("s = %s %s\n", s->kind(), s->toChars());
- e = resolve(exp->loc, sc, s, true);
- }
- else
- assert(0);
-
- if (global.params.vcomplex)
- exp->type->checkComplexTransition(exp->loc);
-
- result = e;
- }
-
- void visit(ScopeExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- ScopeDsymbol *sds2 = exp->sds;
- TemplateInstance *ti = sds2->isTemplateInstance();
- while (ti)
- {
- WithScopeSymbol *withsym;
- if (!ti->findTempDecl(sc, &withsym) ||
- !ti->semanticTiargs(sc))
- return setError();
- if (withsym && withsym->withstate->wthis)
- {
- Expression *e = new VarExp(exp->loc, withsym->withstate->wthis);
- e = new DotTemplateInstanceExp(exp->loc, e, ti);
- result = expressionSemantic(e, sc);
- return;
- }
- if (ti->needsTypeInference(sc))
- {
- if (TemplateDeclaration *td = ti->tempdecl->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)
- {
- Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
- result = expressionSemantic(e, sc);
- return;
- }
- }
- else if (OverloadSet *os = ti->tempdecl->isOverloadSet())
- {
- FuncDeclaration *fdthis = hasThis(sc);
- AggregateDeclaration *ad = os->parent->isAggregateDeclaration();
- if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad)
- {
- Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
- result = expressionSemantic(e, sc);
- return;
- }
- }
- // ti is an instance which requires IFTI.
- exp->sds = ti;
- exp->type = Type::tvoid;
- result = exp;
- return;
- }
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors)
- return setError();
-
- Dsymbol *s = ti->toAlias();
- if (s == ti)
- {
- exp->sds = ti;
- exp->type = Type::tvoid;
- result = exp;
- return;
- }
- sds2 = s->isScopeDsymbol();
- if (sds2)
- {
- ti = sds2->isTemplateInstance();
- //printf("+ sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
- continue;
- }
-
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- if (!v->type)
- {
- exp->error("forward reference of %s %s", v->kind(), v->toChars());
- return setError();
- }
- if ((v->storage_class & STCmanifest) && v->_init)
- {
- /* When an instance that will be converted to a constant exists,
- * the instance representation "foo!tiargs" is treated like a
- * variable name, and its recursive appearance check (note that
- * it's equivalent with a recursive instantiation of foo) is done
- * separately from the circular initialization check for the
- * eponymous enum variable declaration.
- *
- * template foo(T) {
- * enum bool foo = foo; // recursive definition check (v.inuse)
- * }
- * template bar(T) {
- * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
- * }
- */
- if (ti->inuse)
- {
- exp->error("recursive expansion of %s `%s`", ti->kind(), ti->toPrettyChars());
- return setError();
- }
-
- Expression *e = v->expandInitializer(exp->loc);
- ti->inuse++;
- e = expressionSemantic(e, sc);
- ti->inuse--;
- result = e;
- return;
- }
- }
-
- //printf("s = %s, '%s'\n", s->kind(), s->toChars());
- Expression *e = resolve(exp->loc, sc, s, true);
- //printf("-1ScopeExp::semantic()\n");
- result = e;
- return;
- }
-
- //printf("sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
- //printf("\tparent = '%s'\n", sds2->parent->toChars());
- dsymbolSemantic(sds2, sc);
-
- if (Type *t = sds2->getType()) // (Aggregate|Enum)Declaration
- {
- Expression *ex = new TypeExp(exp->loc, t);
- result = expressionSemantic(ex, sc);
- return;
- }
-
- if (TemplateDeclaration *td = sds2->isTemplateDeclaration())
- {
- result = expressionSemantic(new TemplateExp(exp->loc, td), sc);
- return;
- }
-
- exp->sds = sds2;
- exp->type = Type::tvoid;
- //printf("-2ScopeExp::semantic() %s\n", exp->toChars());
- result = exp;
- }
-
- void visit(NewExp *exp)
- {
- if (exp->type) // if semantic() already run
- {
- result = exp;
- return;
- }
-
- // Bugzilla 11581: With the syntax `new T[edim]` or `thisexp.new T[edim]`,
- // T should be analyzed first and edim should go into arguments iff it's
- // not a tuple.
- Expression *edim = NULL;
- if (!exp->arguments && exp->newtype->ty == Tsarray)
- {
- edim = ((TypeSArray *)exp->newtype)->dim;
- exp->newtype = ((TypeNext *)exp->newtype)->next;
- }
-
- ClassDeclaration *cdthis = NULL;
- if (exp->thisexp)
- {
- exp->thisexp = expressionSemantic(exp->thisexp, sc);
- if (exp->thisexp->op == TOKerror)
- return setError();
- cdthis = exp->thisexp->type->isClassHandle();
- if (!cdthis)
- {
- exp->error("`this` for nested class must be a class type, not %s", exp->thisexp->type->toChars());
- return setError();
- }
-
- sc = sc->push(cdthis);
- exp->type = typeSemantic(exp->newtype, exp->loc, sc);
- sc = sc->pop();
- }
- else
- {
- exp->type = typeSemantic(exp->newtype, exp->loc, sc);
- }
- if (exp->type->ty == Terror)
- return setError();
-
- if (edim)
- {
- if (exp->type->toBasetype()->ty == Ttuple)
- {
- // --> new T[edim]
- exp->type = new TypeSArray(exp->type, edim);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
- if (exp->type->ty == Terror)
- return setError();
- }
- else
- {
- // --> new T[](edim)
- exp->arguments = new Expressions();
- exp->arguments->push(edim);
- exp->type = exp->type->arrayOf();
- }
- }
-
- exp->newtype = exp->type; // in case type gets cast to something else
- Type *tb = exp->type->toBasetype();
- //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco);
-
- if (arrayExpressionSemantic(exp->newargs, sc) ||
- preFunctionParameters(sc, exp->newargs))
- {
- return setError();
- }
- if (arrayExpressionSemantic(exp->arguments, sc) ||
- preFunctionParameters(sc, exp->arguments))
- {
- return setError();
- }
-
- if (exp->thisexp && tb->ty != Tclass)
- {
- exp->error("e.new is only for allocating nested classes, not %s", tb->toChars());
- return setError();
- }
-
- size_t nargs = exp->arguments ? exp->arguments->length : 0;
- Expression *newprefix = NULL;
-
- if (tb->ty == Tclass)
- {
- ClassDeclaration *cd = ((TypeClass *)tb)->sym;
- cd->size(exp->loc);
- if (cd->sizeok != SIZEOKdone)
- return setError();
- if (!cd->ctor)
- cd->ctor = cd->searchCtor();
- if (cd->noDefaultCtor && !nargs && !cd->defaultCtor)
- {
- exp->error("default construction is disabled for type %s", cd->type->toChars());
- return setError();
- }
-
- if (cd->isInterfaceDeclaration())
- {
- exp->error("cannot create instance of interface %s", cd->toChars());
- return setError();
- }
- if (cd->isAbstract())
- {
- exp->error("cannot create instance of abstract class %s", cd->toChars());
- for (size_t i = 0; i < cd->vtbl.length; i++)
- {
- FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration();
- if (fd && fd->isAbstract())
- errorSupplemental(exp->loc, "function `%s` is not implemented", fd->toFullSignature());
- }
- return setError();
- }
- // checkDeprecated() is already done in newtype->semantic().
-
- if (cd->isNested())
- {
- /* We need a 'this' pointer for the nested class.
- * Ensure we have the right one.
- */
- Dsymbol *s = cd->toParent2();
- //printf("cd isNested, parent = %s '%s'\n", s->kind(), s->toPrettyChars());
- if (ClassDeclaration *cdn = s->isClassDeclaration())
- {
- if (!cdthis)
- {
- // Supply an implicit 'this' and try again
- exp->thisexp = new ThisExp(exp->loc);
- for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
- {
- if (!sp)
- {
- exp->error("outer class %s `this` needed to `new` nested class %s", cdn->toChars(), cd->toChars());
- return setError();
- }
- ClassDeclaration *cdp = sp->isClassDeclaration();
- if (!cdp)
- continue;
- if (cdp == cdn || cdn->isBaseOf(cdp, NULL))
- break;
- // Add a '.outer' and try again
- exp->thisexp = new DotIdExp(exp->loc, exp->thisexp, Id::outer);
- }
- exp->thisexp = expressionSemantic(exp->thisexp, sc);
- if (exp->thisexp->op == TOKerror)
- return setError();
- cdthis = exp->thisexp->type->isClassHandle();
- }
- if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL))
- {
- //printf("cdthis = %s\n", cdthis->toChars());
- exp->error("`this` for nested class must be of type %s, not %s",
- cdn->toChars(), exp->thisexp->type->toChars());
- return setError();
- }
- if (!MODimplicitConv(exp->thisexp->type->mod, exp->newtype->mod))
- {
- exp->error("nested type %s should have the same or weaker constancy as enclosing type %s",
- exp->newtype->toChars(), exp->thisexp->type->toChars());
- return setError();
- }
- }
- else if (exp->thisexp)
- {
- exp->error("e.new is only for allocating nested classes");
- return setError();
- }
- else if (FuncDeclaration *fdn = s->isFuncDeclaration())
- {
- // make sure the parent context fdn of cd is reachable from sc
- if (checkNestedRef(sc->parent, fdn))
- {
- exp->error("outer function context of %s is needed to `new` nested class %s",
- fdn->toPrettyChars(), cd->toPrettyChars());
- return setError();
- }
- }
- else
- assert(0);
- }
- else if (exp->thisexp)
- {
- exp->error("e.new is only for allocating nested classes");
- return setError();
- }
-
- if (cd->aggNew)
- {
- // Prepend the size argument to newargs[]
- Expression *e = new IntegerExp(exp->loc, cd->size(exp->loc), Type::tsize_t);
- if (!exp->newargs)
- exp->newargs = new Expressions();
- exp->newargs->shift(e);
-
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->aggNew, NULL, tb, exp->newargs);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(cd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- Type *rettype;
- if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
- return setError();
-
- exp->allocator = f->isNewDeclaration();
- assert(exp->allocator);
- }
- else
- {
- if (exp->newargs && exp->newargs->length)
- {
- exp->error("no allocator for %s", cd->toChars());
- return setError();
- }
- }
-
- if (cd->ctor)
- {
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->ctor, NULL, tb, exp->arguments, 0);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(cd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- if (!exp->arguments)
- exp->arguments = new Expressions();
- if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
- return setError();
-
- exp->member = f->isCtorDeclaration();
- assert(exp->member);
- }
- else
- {
- if (nargs)
- {
- exp->error("no constructor for %s", cd->toChars());
- return setError();
- }
-
- // https://issues.dlang.org/show_bug.cgi?id=19941
- // Run semantic on all field initializers to resolve any forward
- // references. This is the same as done for structs in sd->fill().
- for (ClassDeclaration *c = cd; c; c = c->baseClass)
- {
- for (size_t i = 0; i < c->fields.length; i++)
- {
- VarDeclaration *v = c->fields[i];
- if (v->inuse || v->_scope == NULL || v->_init == NULL ||
- v->_init->isVoidInitializer())
- continue;
- v->inuse++;
- v->_init = initializerSemantic(v->_init, v->_scope, v->type, INITinterpret);
- v->inuse--;
- }
- }
- }
- }
- else if (tb->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- sd->size(exp->loc);
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
- if (sd->noDefaultCtor && !nargs)
- {
- exp->error("default construction is disabled for type %s", sd->type->toChars());
- return setError();
- }
- // checkDeprecated() is already done in newtype->semantic().
-
- if (sd->aggNew)
- {
- // Prepend the uint size argument to newargs[]
- Expression *e = new IntegerExp(exp->loc, sd->size(exp->loc), Type::tsize_t);
- if (!exp->newargs)
- exp->newargs = new Expressions();
- exp->newargs->shift(e);
-
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->aggNew, NULL, tb, exp->newargs);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(sd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- Type *rettype;
- if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
- return setError();
-
- exp->allocator = f->isNewDeclaration();
- assert(exp->allocator);
- }
- else
- {
- if (exp->newargs && exp->newargs->length)
- {
- exp->error("no allocator for %s", sd->toChars());
- return setError();
- }
- }
-
- if (sd->ctor && nargs)
- {
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->ctor, NULL, tb, exp->arguments, 0);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(sd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- if (!exp->arguments)
- exp->arguments = new Expressions();
- if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
- return setError();
-
- exp->member = f->isCtorDeclaration();
- assert(exp->member);
-
- if (checkFrameAccess(exp->loc, sc, sd, sd->fields.length))
- return setError();
- }
- else
- {
- if (!exp->arguments)
- exp->arguments = new Expressions();
-
- if (!sd->fit(exp->loc, sc, exp->arguments, tb))
- return setError();
- if (!sd->fill(exp->loc, exp->arguments, false))
- return setError();
- if (checkFrameAccess(exp->loc, sc, sd, exp->arguments ? exp->arguments->length : 0))
- return setError();
- }
-
- exp->type = exp->type->pointerTo();
- }
- else if (tb->ty == Tarray && nargs)
- {
- Type *tn = tb->nextOf()->baseElemOf();
- Dsymbol *s = tn->toDsymbol(sc);
- AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
- if (ad && ad->noDefaultCtor)
- {
- exp->error("default construction is disabled for type %s", tb->nextOf()->toChars());
- return setError();
- }
- for (size_t i = 0; i < nargs; i++)
- {
- if (tb->ty != Tarray)
- {
- exp->error("too many arguments for array");
- return setError();
- }
-
- Expression *arg = (*exp->arguments)[i];
- arg = resolveProperties(sc, arg);
- arg = arg->implicitCastTo(sc, Type::tsize_t);
- arg = arg->optimize(WANTvalue);
- if (arg->op == TOKint64 && (sinteger_t)arg->toInteger() < 0)
- {
- exp->error("negative array index %s", arg->toChars());
- return setError();
- }
- (*exp->arguments)[i] = arg;
- tb = ((TypeDArray *)tb)->next->toBasetype();
- }
- }
- else if (tb->isscalar())
- {
- if (!nargs)
- {
- }
- else if (nargs == 1)
- {
- Expression *e = (*exp->arguments)[0];
- e = e->implicitCastTo(sc, tb);
- (*exp->arguments)[0] = e;
- }
- else
- {
- exp->error("more than one argument for construction of %s", exp->type->toChars());
- return setError();
- }
-
- exp->type = exp->type->pointerTo();
- }
- else
- {
- exp->error("new can only create structs, dynamic arrays or class objects, not %s's", exp->type->toChars());
- return setError();
- }
-
- //printf("NewExp: '%s'\n", toChars());
- //printf("NewExp:type '%s'\n", exp->type->toChars());
- semanticTypeInfo(sc, exp->type);
-
- if (newprefix)
- {
- result = Expression::combine(newprefix, exp);
- return;
- }
- result = exp;
- }
-
- void visit(NewAnonClassExp *e)
- {
- Expression *d = new DeclarationExp(e->loc, e->cd);
- sc = sc->push(); // just create new scope
- sc->flags &= ~SCOPEctfe; // temporary stop CTFE
- d = expressionSemantic(d, sc);
- sc = sc->pop();
-
- if (!e->cd->errors && sc->intypeof && !sc->parent->inNonRoot())
- {
- ScopeDsymbol *sds = sc->tinst ? (ScopeDsymbol *)sc->tinst : sc->_module;
- sds->members->push(e->cd);
- }
-
- Expression *n = new NewExp(e->loc, e->thisexp, e->newargs, e->cd->type, e->arguments);
-
- Expression *c = new CommaExp(e->loc, d, n);
- result = expressionSemantic(c, sc);
- }
-
- void visit(SymOffExp *e)
- {
- //dsymbolSemantic(var, sc);
- if (!e->type)
- e->type = e->var->type->pointerTo();
- if (VarDeclaration *v = e->var->isVarDeclaration())
- {
- if (v->checkNestedReference(sc, e->loc))
- return setError();
- }
- else if (FuncDeclaration *f = e->var->isFuncDeclaration())
- {
- if (f->checkNestedReference(sc, e->loc))
- return setError();
- }
- result = e;
- }
-
- void visit(VarExp *e)
- {
- VarDeclaration *vd = e->var->isVarDeclaration();
- FuncDeclaration *fd = e->var->isFuncDeclaration();
-
- if (fd)
- {
- //printf("L%d fd = %s\n", __LINE__, f->toChars());
- if (!fd->functionSemantic())
- return setError();
- }
-
- if (!e->type)
- e->type = e->var->type;
-
- if (e->type && !e->type->deco)
- {
- Declaration *decl = e->var->isDeclaration();
- if (decl)
- decl->inuse++;
- e->type = typeSemantic(e->type, e->loc, sc);
- if (decl)
- decl->inuse--;
- }
-
- /* Fix for 1161 doesn't work because it causes protection
- * problems when instantiating imported templates passing private
- * variables as alias template parameters.
- */
- //checkAccess(e->loc, sc, NULL, e->var);
-
- if (vd)
- {
- if (vd->checkNestedReference(sc, e->loc))
- return setError();
- // Bugzilla 12025: If the variable is not actually used in runtime code,
- // the purity violation error is redundant.
- //checkPurity(sc, vd);
- }
- else if (fd)
- {
- // TODO: If fd isn't yet resolved its overload, the checkNestedReference
- // call would cause incorrect validation.
- // Maybe here should be moved in CallExp, or AddrExp for functions.
- if (fd->checkNestedReference(sc, e->loc))
- return setError();
- }
- else if (e->var->isOverDeclaration())
- {
- e->type = Type::tvoid; // ambiguous type?
- }
-
- result = e;
- }
-
- void visit(TupleExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (exp->e0)
- exp->e0 = expressionSemantic(exp->e0, sc);
-
- // Run semantic() on each argument
- bool err = false;
- for (size_t i = 0; i < exp->exps->length; i++)
- {
- Expression *e = (*exp->exps)[i];
- e = expressionSemantic(e, sc);
- if (!e->type)
- {
- exp->error("%s has no value", e->toChars());
- err = true;
- }
- else if (e->op == TOKerror)
- err = true;
- else
- (*exp->exps)[i] = e;
- }
- if (err)
- return setError();
-
- expandTuples(exp->exps);
- exp->type = new TypeTuple(exp->exps);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
- //printf("-TupleExp::semantic(%s)\n", exp->toChars());
- result = exp;
- }
-
- void visit(FuncExp *exp)
- {
- Expression *e = exp;
-
- sc = sc->push(); // just create new scope
- sc->flags &= ~SCOPEctfe; // temporary stop CTFE
- sc->protection = Prot(Prot::public_); // Bugzilla 12506
-
- if (!exp->type || exp->type == Type::tvoid)
- {
- /* fd->treq might be incomplete type,
- * so should not semantic it.
- * void foo(T)(T delegate(int) dg){}
- * foo(a=>a); // in IFTI, treq == T delegate(int)
- */
- //if (exp->fd->treq)
- // exp->fd->treq = typeSemantic(exp->fd->treq, exp->loc, sc);
-
- exp->genIdent(sc);
-
- // Set target of return type inference
- if (exp->fd->treq && !exp->fd->type->nextOf())
- {
- TypeFunction *tfv = NULL;
- if (exp->fd->treq->ty == Tdelegate ||
- (exp->fd->treq->ty == Tpointer && exp->fd->treq->nextOf()->ty == Tfunction))
- tfv = (TypeFunction *)exp->fd->treq->nextOf();
- if (tfv)
- {
- TypeFunction *tfl = (TypeFunction *)exp->fd->type;
- tfl->next = tfv->nextOf();
- }
- }
-
- //printf("td = %p, treq = %p\n", exp->td, exp->fd->treq);
- if (exp->td)
- {
- assert(exp->td->parameters && exp->td->parameters->length);
- dsymbolSemantic(exp->td, sc);
- exp->type = Type::tvoid; // temporary type
-
- if (exp->fd->treq) // defer type determination
- {
- FuncExp *fe;
- if (exp->matchType(exp->fd->treq, sc, &fe) > MATCHnomatch)
- e = fe;
- else
- e = new ErrorExp();
- }
- goto Ldone;
- }
-
- unsigned olderrors = global.errors;
- dsymbolSemantic(exp->fd, sc);
- if (olderrors == global.errors)
- {
- semantic2(exp->fd, sc);
- if (olderrors == global.errors)
- semantic3(exp->fd, sc);
- }
- if (olderrors != global.errors)
- {
- if (exp->fd->type && exp->fd->type->ty == Tfunction && !exp->fd->type->nextOf())
- ((TypeFunction *)exp->fd->type)->next = Type::terror;
- e = new ErrorExp();
- goto Ldone;
- }
-
- // Type is a "delegate to" or "pointer to" the function literal
- if ((exp->fd->isNested() && exp->fd->tok == TOKdelegate) ||
- (exp->tok == TOKreserved && exp->fd->treq && exp->fd->treq->ty == Tdelegate))
- {
- exp->type = new TypeDelegate(exp->fd->type);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
-
- exp->fd->tok = TOKdelegate;
- }
- else
- {
- exp->type = new TypePointer(exp->fd->type);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
- //exp->type = exp->fd->type->pointerTo();
-
- /* A lambda expression deduced to function pointer might become
- * to a delegate literal implicitly.
- *
- * auto foo(void function() fp) { return 1; }
- * assert(foo({}) == 1);
- *
- * So, should keep fd->tok == TOKreserve if fd->treq == NULL.
- */
- if (exp->fd->treq && exp->fd->treq->ty == Tpointer)
- {
- // change to non-nested
- exp->fd->tok = TOKfunction;
- exp->fd->vthis = NULL;
- }
- }
- exp->fd->tookAddressOf++;
- }
- Ldone:
- sc = sc->pop();
- result = e;
- }
-
- // used from CallExp::semantic()
- Expression *callExpSemantic(FuncExp *exp, Scope *sc, Expressions *arguments)
- {
- if ((!exp->type || exp->type == Type::tvoid) && exp->td && arguments && arguments->length)
- {
- for (size_t k = 0; k < arguments->length; k++)
- { Expression *checkarg = (*arguments)[k];
- if (checkarg->op == TOKerror)
- return checkarg;
- }
-
- exp->genIdent(sc);
-
- assert(exp->td->parameters && exp->td->parameters->length);
- dsymbolSemantic(exp->td, sc);
-
- TypeFunction *tfl = (TypeFunction *)exp->fd->type;
- size_t dim = tfl->parameterList.length();
- if (arguments->length < dim)
- { // Default arguments are always typed, so they don't need inference.
- Parameter *p = tfl->parameterList[arguments->length];
- if (p->defaultArg)
- dim = arguments->length;
- }
-
- if ((tfl->parameterList.varargs == VARARGnone && arguments->length == dim) ||
- (tfl->parameterList.varargs != VARARGnone && arguments->length >= dim))
- {
- Objects *tiargs = new Objects();
- tiargs->reserve(exp->td->parameters->length);
-
- for (size_t i = 0; i < exp->td->parameters->length; i++)
- {
- TemplateParameter *tp = (*exp->td->parameters)[i];
- for (size_t u = 0; u < dim; u++)
- { Parameter *p = tfl->parameterList[u];
- if (p->type->ty == Tident &&
- ((TypeIdentifier *)p->type)->ident == tp->ident)
- { Expression *e = (*arguments)[u];
- tiargs->push(e->type);
- u = dim; // break inner loop
- }
- }
- }
-
- TemplateInstance *ti = new TemplateInstance(exp->loc, exp->td, tiargs);
- Expression *se = new ScopeExp(exp->loc, ti);
- return expressionSemantic(se, sc);
- }
- exp->error("cannot infer function literal type");
- return new ErrorExp();
- }
- return expressionSemantic(exp, sc);
- }
-
- void visit(DeclarationExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- unsigned olderrors = global.errors;
-
- /* This is here to support extern(linkage) declaration,
- * where the extern(linkage) winds up being an AttribDeclaration
- * wrapper.
- */
- Dsymbol *s = e->declaration;
-
- while (1)
- {
- AttribDeclaration *ad = s->isAttribDeclaration();
- if (ad)
- {
- if (ad->decl && ad->decl->length == 1)
- {
- s = (*ad->decl)[0];
- continue;
- }
- }
- break;
- }
-
- VarDeclaration *v = s->isVarDeclaration();
- if (v)
- {
- // Do semantic() on initializer first, so:
- // int a = a;
- // will be illegal.
- dsymbolSemantic(e->declaration, sc);
- s->parent = sc->parent;
- }
-
- //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc);
- // Insert into both local scope and function scope.
- // Must be unique in both.
- if (s->ident)
- {
- if (!sc->insert(s))
- {
- e->error("declaration %s is already defined", s->toPrettyChars());
- return setError();
- }
- else if (sc->func)
- {
- // Bugzilla 11720 - include Dataseg variables
- if ((s->isFuncDeclaration() ||
- s->isAggregateDeclaration() ||
- s->isEnumDeclaration() ||
- (v && v->isDataseg())) &&
- !sc->func->localsymtab->insert(s))
- {
- e->error("declaration %s is already defined in another scope in %s",
- s->toPrettyChars(), sc->func->toChars());
- return setError();
- }
- else
- {
- // Disallow shadowing
- for (Scope *scx = sc->enclosing; scx && (scx->func == sc->func || (scx->func && sc->func->fes)); scx = scx->enclosing)
- {
- Dsymbol *s2;
- if (scx->scopesym && scx->scopesym->symtab &&
- (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
- s != s2)
- {
- // allow STClocal symbols to be shadowed
- // TODO: not reallly an optimal design
- Declaration *decl = s2->isDeclaration();
- if (!decl || !(decl->storage_class & STClocal))
- {
- if (sc->func->fes)
- {
- e->deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.",
- s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
- }
- else
- {
- e->error("%s %s is shadowing %s %s",
- s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
- return setError();
- }
- }
- }
- }
- }
- }
- }
- if (!s->isVarDeclaration())
- {
- Scope *sc2 = sc;
- if (sc2->stc & (STCpure | STCnothrow | STCnogc))
- sc2 = sc->push();
- sc2->stc &= ~(STCpure | STCnothrow | STCnogc);
- dsymbolSemantic(e->declaration, sc2);
- if (sc2 != sc)
- sc2->pop();
- s->parent = sc->parent;
- }
- if (global.errors == olderrors)
- {
- semantic2(e->declaration, sc);
- if (global.errors == olderrors)
- {
- semantic3(e->declaration, sc);
- }
- }
- // todo: error in declaration should be propagated.
-
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(TypeidExp *exp)
- {
- Type *ta = isType(exp->obj);
- Expression *ea = isExpression(exp->obj);
- Dsymbol *sa = isDsymbol(exp->obj);
-
- //printf("ta %p ea %p sa %p\n", ta, ea, sa);
-
- if (ta)
- {
- ta->resolve(exp->loc, sc, &ea, &ta, &sa, true);
- }
-
- if (ea)
- {
- if (Dsymbol *sym = getDsymbol(ea))
- ea = resolve(exp->loc, sc, sym, false);
- else
- ea = expressionSemantic(ea, sc);
- ea = resolveProperties(sc, ea);
- ta = ea->type;
- if (ea->op == TOKtype)
- ea = NULL;
- }
-
- if (!ta)
- {
- //printf("ta %p ea %p sa %p\n", ta, ea, sa);
- exp->error("no type for typeid(%s)", ea ? ea->toChars() : (sa ? sa->toChars() : ""));
- return setError();
- }
-
- if (global.params.vcomplex)
- ta->checkComplexTransition(exp->loc);
-
- Expression *e;
- if (ea && ta->toBasetype()->ty == Tclass)
- {
- if (!Type::typeinfoclass)
- {
- error(exp->loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
- e = new ErrorExp();
- }
- else
- {
- /* Get the dynamic type, which is .classinfo
- */
- ea = expressionSemantic(ea, sc);
- e = new TypeidExp(ea->loc, ea);
- e->type = Type::typeinfoclass->type;
- }
- }
- else if (ta->ty == Terror)
- {
- e = new ErrorExp();
- }
- else
- {
- // Handle this in the glue layer
- e = new TypeidExp(exp->loc, ta);
- e->type = getTypeInfoType(exp->loc, ta, sc);
-
- semanticTypeInfo(sc, ta);
-
- if (ea)
- {
- e = new CommaExp(exp->loc, ea, e); // execute ea
- e = expressionSemantic(e, sc);
- }
- }
- result = e;
- }
-
- void visit(TraitsExp *e)
- {
- result = semanticTraits(e, sc);
- }
-
- void visit(HaltExp *e)
- {
- e->type = Type::tnoreturn;
- result = e;
- }
-
- void visit(IsExp *e)
- {
- /* is(targ id tok tspec)
- * is(targ id : tok2)
- * is(targ id == tok2)
- */
-
- //printf("IsExp::semantic(%s)\n", toChars());
- if (e->id && !(sc->flags & SCOPEcondition))
- {
- e->error("can only declare type aliases within static if conditionals or static asserts");
- return setError();
- }
-
- Type *tded = NULL;
- if (e->tok2 == TOKpackage || e->tok2 == TOKmodule) // These is() expressions are special because they can work on modules, not just types.
- {
- const unsigned oldErrors = global.startGagging();
- Dsymbol *sym = e->targ->toDsymbol(sc);
- global.endGagging(oldErrors);
- if (sym == NULL)
- goto Lno;
- Package *p = resolveIsPackage(sym);
- if (p == NULL)
- goto Lno;
- if (e->tok2 == TOKpackage && p->isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
- goto Lno;
- else if(e->tok2 == TOKmodule && !(p->isModule() || p->isPackageMod()))
- goto Lno;
- tded = e->targ;
- goto Lyes;
- }
-
- {
- Scope *sc2 = sc->copy(); // keep sc->flags
- sc2->tinst = NULL;
- sc2->minst = NULL;
- sc2->flags |= SCOPEfullinst;
- Type *t = e->targ->trySemantic(e->loc, sc2);
- sc2->pop();
- if (!t) // errors, so condition is false
- goto Lno;
- e->targ = t;
- }
-
- if (e->tok2 != TOKreserved)
- {
- switch (e->tok2)
- {
- case TOKstruct:
- if (e->targ->ty != Tstruct)
- goto Lno;
- if (((TypeStruct *)e->targ)->sym->isUnionDeclaration())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKunion:
- if (e->targ->ty != Tstruct)
- goto Lno;
- if (!((TypeStruct *)e->targ)->sym->isUnionDeclaration())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKclass:
- if (e->targ->ty != Tclass)
- goto Lno;
- if (((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKinterface:
- if (e->targ->ty != Tclass)
- goto Lno;
- if (!((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
- goto Lno;
- tded = e->targ;
- break;
- case TOKconst:
- if (!e->targ->isConst())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKimmutable:
- if (!e->targ->isImmutable())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKshared:
- if (!e->targ->isShared())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKwild:
- if (!e->targ->isWild())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKsuper:
- // If class or interface, get the base class and interfaces
- if (e->targ->ty != Tclass)
- goto Lno;
- else
- {
- ClassDeclaration *cd = ((TypeClass *)e->targ)->sym;
- Parameters *args = new Parameters;
- args->reserve(cd->baseclasses->length);
- if (cd->semanticRun < PASSsemanticdone)
- dsymbolSemantic(cd, NULL);
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *b = (*cd->baseclasses)[i];
- args->push(new Parameter(STCin, b->type, NULL, NULL, NULL));
- }
- tded = new TypeTuple(args);
- }
- break;
-
- case TOKenum:
- if (e->targ->ty != Tenum)
- goto Lno;
- if (e->id)
- tded = ((TypeEnum *)e->targ)->sym->getMemtype(e->loc);
- else
- tded = e->targ;
- if (tded->ty == Terror)
- return setError();
- break;
-
- case TOKdelegate:
- if (e->targ->ty != Tdelegate)
- goto Lno;
- tded = ((TypeDelegate *)e->targ)->next; // the underlying function type
- break;
-
- case TOKfunction:
- case TOKparameters:
- {
- if (e->targ->ty != Tfunction)
- goto Lno;
- tded = e->targ;
-
- /* Generate tuple from function parameter types.
- */
- assert(tded->ty == Tfunction);
- TypeFunction *tdedf = (TypeFunction *)tded;
- size_t dim = tdedf->parameterList.length();
- Parameters *args = new Parameters;
- args->reserve(dim);
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *arg = tdedf->parameterList[i];
- assert(arg && arg->type);
- /* If one of the default arguments was an error,
- don't return an invalid tuple
- */
- if (e->tok2 == TOKparameters && arg->defaultArg &&
- arg->defaultArg->op == TOKerror)
- return setError();
- args->push(new Parameter(arg->storageClass, arg->type,
- (e->tok2 == TOKparameters) ? arg->ident : NULL,
- (e->tok2 == TOKparameters) ? arg->defaultArg : NULL,
- arg->userAttribDecl));
- }
- tded = new TypeTuple(args);
- break;
- }
- case TOKreturn:
- /* Get the 'return type' for the function,
- * delegate, or pointer to function.
- */
- if (e->targ->ty == Tfunction)
- tded = ((TypeFunction *)e->targ)->next;
- else if (e->targ->ty == Tdelegate)
- {
- tded = ((TypeDelegate *)e->targ)->next;
- tded = ((TypeFunction *)tded)->next;
- }
- else if (e->targ->ty == Tpointer &&
- ((TypePointer *)e->targ)->next->ty == Tfunction)
- {
- tded = ((TypePointer *)e->targ)->next;
- tded = ((TypeFunction *)tded)->next;
- }
- else
- goto Lno;
- break;
-
- case TOKargTypes:
- /* Generate a type tuple of the equivalent types used to determine if a
- * function argument of this type can be passed in registers.
- * The results of this are highly platform dependent, and intended
- * primarly for use in implementing va_arg().
- */
- tded = target.toArgTypes(e->targ);
- if (!tded)
- goto Lno; // not valid for a parameter
- break;
-
- case TOKvector:
- if (e->targ->ty != Tvector)
- goto Lno;
- tded = ((TypeVector *)e->targ)->basetype;
- break;
-
- default:
- assert(0);
- }
- goto Lyes;
- }
- else if (e->tspec && !e->id && !(e->parameters && e->parameters->length))
- {
- /* Evaluate to true if targ matches tspec
- * is(targ == tspec)
- * is(targ : tspec)
- */
- e->tspec = typeSemantic(e->tspec, e->loc, sc);
- //printf("targ = %s, %s\n", e->targ->toChars(), e->targ->deco);
- //printf("tspec = %s, %s\n", e->tspec->toChars(), e->tspec->deco);
- if (e->tok == TOKcolon)
- {
- if (e->targ->implicitConvTo(e->tspec))
- goto Lyes;
- else
- goto Lno;
- }
- else /* == */
- {
- if (e->targ->equals(e->tspec))
- goto Lyes;
- else
- goto Lno;
- }
- }
- else if (e->tspec)
- {
- /* Evaluate to true if targ matches tspec.
- * If true, declare id as an alias for the specialized type.
- * is(targ == tspec, tpl)
- * is(targ : tspec, tpl)
- * is(targ id == tspec)
- * is(targ id : tspec)
- * is(targ id == tspec, tpl)
- * is(targ id : tspec, tpl)
- */
-
- Identifier *tid = e->id ? e->id : Identifier::generateId("__isexp_id");
- e->parameters->insert(0, new TemplateTypeParameter(e->loc, tid, NULL, NULL));
-
- Objects dedtypes;
- dedtypes.setDim(e->parameters->length);
- dedtypes.zero();
-
- MATCH m = deduceType(e->targ, sc, e->tspec, e->parameters, &dedtypes);
- //printf("targ: %s\n", e->targ->toChars());
- //printf("tspec: %s\n", e->tspec->toChars());
- if (m <= MATCHnomatch ||
- (m != MATCHexact && e->tok == TOKequal))
- {
- goto Lno;
- }
- else
- {
- tded = (Type *)dedtypes[0];
- if (!tded)
- tded = e->targ;
- Objects tiargs;
- tiargs.setDim(1);
- tiargs[0] = e->targ;
-
- /* Declare trailing parameters
- */
- for (size_t i = 1; i < e->parameters->length; i++)
- {
- TemplateParameter *tp = (*e->parameters)[i];
- Declaration *s = NULL;
-
- m = tp->matchArg(e->loc, sc, &tiargs, i, e->parameters, &dedtypes, &s);
- if (m <= MATCHnomatch)
- goto Lno;
- dsymbolSemantic(s, sc);
- if (!sc->insert(s))
- e->error("declaration %s is already defined", s->toChars());
-
- unSpeculative(sc, s);
- }
- goto Lyes;
- }
- }
- else if (e->id)
- {
- /* Declare id as an alias for type targ. Evaluate to true
- * is(targ id)
- */
- tded = e->targ;
- goto Lyes;
- }
-
- Lyes:
- if (e->id)
- {
- Dsymbol *s;
- Tuple *tup = isTuple(tded);
- if (tup)
- s = new TupleDeclaration(e->loc, e->id, &(tup->objects));
- else
- s = new AliasDeclaration(e->loc, e->id, tded);
- dsymbolSemantic(s, sc);
- /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
- * More investigation is needed.
- */
- if (!tup && !sc->insert(s))
- e->error("declaration %s is already defined", s->toChars());
-
- unSpeculative(sc, s);
- }
- //printf("Lyes\n");
- result = new IntegerExp(e->loc, 1, Type::tbool);
- return;
-
- Lno:
- //printf("Lno\n");
- result = new IntegerExp(e->loc, 0, Type::tbool);
- }
-
- void visit(BinAssignExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
- return setError();
-
- if (exp->e1->op == TOKarraylength)
- {
- // arr.length op= e2;
- e = rewriteOpAssign(exp);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
- {
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- if (exp->e1->op == TOKslice)
- ((SliceExp *)exp->e1)->arrayop = true;
-
- // T[] op= ...
- if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
- {
- // T[] op= T
- exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
- }
- else if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- exp->type = exp->e1->type;
- result = arrayOp(exp, sc);
- return;
- }
-
- exp->e1 = expressionSemantic(exp->e1, sc);
- exp->e1 = exp->e1->optimize(WANTvalue);
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
- exp->type = exp->e1->type;
- if (exp->checkScalar())
- return setError();
-
- int arith = (exp->op == TOKaddass || exp->op == TOKminass || exp->op == TOKmulass ||
- exp->op == TOKdivass || exp->op == TOKmodass || exp->op == TOKpowass);
- int bitwise = (exp->op == TOKandass || exp->op == TOKorass || exp->op == TOKxorass);
- int shift = (exp->op == TOKshlass || exp->op == TOKshrass || exp->op == TOKushrass);
-
- if (bitwise && exp->type->toBasetype()->ty == Tbool)
- exp->e2 = exp->e2->implicitCastTo(sc, exp->type);
- else if (exp->checkNoBool())
- return setError();
-
- if ((exp->op == TOKaddass || exp->op == TOKminass) &&
- exp->e1->type->toBasetype()->ty == Tpointer &&
- exp->e2->type->toBasetype()->isintegral())
- {
- result = scaleFactor(exp, sc);
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- if (arith && exp->checkArithmeticBin())
- return setError();
- if ((bitwise || shift) && exp->checkIntegralBin())
- return setError();
- if (shift)
- {
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
- }
-
- if (!target.isVectorOpSupported(exp->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- if (exp->e1->op == TOKerror || exp->e2->op == TOKerror)
- return setError();
-
- e = exp->checkOpAssignTypes(sc);
- if (e->op == TOKerror)
- {
- result = e;
- return;
- }
-
- assert(e->op == TOKassign || e == exp);
- result = ((BinExp *)e)->reorderSettingAAElem(sc);
- }
-
-private:
- Expression *compileIt(CompileExp *exp)
- {
- OutBuffer buf;
- if (expressionsToString(buf, sc, exp->exps))
- return NULL;
-
- unsigned errors = global.errors;
- const size_t len = buf.length();
- const char *str = buf.extractChars();
- Parser p(exp->loc, sc->_module, (const utf8_t *)str, len, false);
- p.nextToken();
- //printf("p.loc.linnum = %d\n", p.loc.linnum);
-
- Expression *e = p.parseExpression();
- if (global.errors != errors)
- return NULL;
-
- if (p.token.value != TOKeof)
- {
- exp->error("incomplete mixin expression (%s)", str);
- return NULL;
- }
- return e;
- }
-
-public:
- void visit(CompileExp *exp)
- {
- //printf("CompileExp::semantic('%s')\n", exp->toChars());
- Expression *e = compileIt(exp);
- if (!e)
- return setError();
- result = expressionSemantic(e, sc);
- }
-
- void visit(ImportExp *e)
- {
- StringExp *se = semanticString(sc, e->e1, "file name argument");
- if (!se)
- return setError();
- se = se->toUTF8(sc);
-
- const char *name = (char *)se->string;
- if (!global.params.fileImppath)
- {
- e->error("need -Jpath switch to import text file %s", name);
- return setError();
- }
-
- /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
- * ('Path Traversal') attacks.
- * http://cwe.mitre.org/data/definitions/22.html
- */
-
- name = FileName::safeSearchPath(global.filePath, name);
- if (!name)
- {
- e->error("file %s cannot be found or not in a path specified with -J", se->toChars());
- return setError();
- }
-
- sc->_module->contentImportedFiles.push(name);
- if (global.params.verbose)
- message("file %.*s\t(%s)", (int)se->len, (char *)se->string, name);
- if (global.params.moduleDeps != NULL)
- {
- OutBuffer *ob = global.params.moduleDeps;
- Module* imod = sc->instantiatingModule();
-
- if (!global.params.moduleDepsFile.length)
- ob->writestring("depsFile ");
- ob->writestring(imod->toPrettyChars());
- ob->writestring(" (");
- escapePath(ob, imod->srcfile->toChars());
- ob->writestring(") : ");
- if (global.params.moduleDepsFile.length)
- ob->writestring("string : ");
- ob->writestring((char *) se->string);
- ob->writestring(" (");
- escapePath(ob, name);
- ob->writestring(")");
- ob->writenl();
- }
-
- {
- File f(name);
- if (f.read())
- {
- e->error("cannot read file %s", f.toChars());
- return setError();
- }
- else
- {
- f.ref = 1;
- se = new StringExp(e->loc, f.buffer, f.len);
- }
- }
- result = expressionSemantic(se, sc);
- }
-
- void visit(AssertExp *exp)
- {
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- exp->e1 = resolveProperties(sc, exp->e1);
- // BUG: see if we can do compile time elimination of the Assert
- exp->e1 = exp->e1->optimize(WANTvalue);
- exp->e1 = exp->e1->toBoolean(sc);
- if (exp->msg)
- {
- exp->msg = expressionSemantic(exp->msg, sc);
- exp->msg = resolveProperties(sc, exp->msg);
- exp->msg = exp->msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf());
- exp->msg = exp->msg->optimize(WANTvalue);
- }
-
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->msg && exp->msg->op == TOKerror)
- {
- result = exp->msg;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = exp->msg && checkNonAssignmentArrayOp(exp->msg);
- if (f1 || f2)
- return setError();
-
- if (exp->e1->isBool(false))
- {
- /* This is an `assert(0)` which means halt program execution
- */
- FuncDeclaration *fd = sc->parent->isFuncDeclaration();
- if (fd)
- fd->hasReturnExp |= 4;
- sc->callSuper |= CSXhalt;
- if (sc->fieldinit)
- {
- for (size_t i = 0; i < sc->fieldinit_dim; i++)
- sc->fieldinit[i] |= CSXhalt;
- }
-
- if (global.params.useAssert == CHECKENABLEoff)
- {
- Expression *e = new HaltExp(exp->loc);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- exp->type = Type::tnoreturn;
- }
- else
- exp->type = Type::tvoid;
- result = exp;
- }
-
- void visit(DotIdExp *exp)
- {
- Expression *e = semanticY(exp, sc, 1);
- if (e && isDotOpDispatch(e))
- {
- unsigned errors = global.startGagging();
- e = resolvePropertiesX(sc, e);
- if (global.endGagging(errors))
- e = NULL; /* fall down to UFCS */
- else
- {
- result = e;
- return;
- }
- }
- if (!e) // if failed to find the property
- {
- /* If ident is not a valid property, rewrite:
- * e1.ident
- * as:
- * .ident(e1)
- */
- e = resolveUFCSProperties(sc, exp);
- }
- result = e;
- }
-
- void visit(DotTemplateExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
- if (Expression *ex = unaSemantic(e, sc))
- {
- result = ex;
- return;
- }
- // 'void' like TemplateExp
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(DotVarExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- exp->var = exp->var->toAlias()->isDeclaration();
-
- exp->e1 = expressionSemantic(exp->e1, sc);
-
- if (TupleDeclaration *tup = exp->var->isTupleDeclaration())
- {
- /* Replace:
- * e1.tuple(a, b, c)
- * with:
- * tuple(e1.a, e1.b, e1.c)
- */
- Expression *e0 = NULL;
- Expression *ev = sc->func ? extractSideEffect(sc, "__tup", &e0, exp->e1) : exp->e1;
-
- Expressions *exps = new Expressions;
- exps->reserve(tup->objects->length);
- for (size_t i = 0; i < tup->objects->length; i++)
- {
- RootObject *o = (*tup->objects)[i];
- Expression *e;
- if (o->dyncast() == DYNCAST_EXPRESSION)
- {
- e = (Expression *)o;
- if (e->op == TOKdsymbol)
- {
- Dsymbol *s = ((DsymbolExp *)e)->s;
- e = new DotVarExp(exp->loc, ev, s->isDeclaration());
- }
- }
- else if (o->dyncast() == DYNCAST_DSYMBOL)
- {
- e = new DsymbolExp(exp->loc, (Dsymbol *)o);
- }
- else if (o->dyncast() == DYNCAST_TYPE)
- {
- e = new TypeExp(exp->loc, (Type *)o);
- }
- else
- {
- exp->error("%s is not an expression", o->toChars());
- return setError();
- }
- exps->push(e);
- }
-
- Expression *e = new TupleExp(exp->loc, e0, exps);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- exp->e1 = exp->e1->addDtorHook(sc);
-
- Type *t1 = exp->e1->type;
-
- if (FuncDeclaration *fd = exp->var->isFuncDeclaration())
- {
- // for functions, do checks after overload resolution
- if (!fd->functionSemantic())
- return setError();
-
- /* Bugzilla 13843: If fd obviously has no overloads, we should
- * normalize AST, and it will give a chance to wrap fd with FuncExp.
- */
- if (fd->isNested() || fd->isFuncLiteralDeclaration())
- {
- // (e1, fd)
- Expression *e = resolve(exp->loc, sc, fd, false);
- result = Expression::combine(exp->e1, e);
- return;
- }
-
- exp->type = fd->type;
- assert(exp->type);
- }
- else if (exp->var->isOverDeclaration())
- {
- exp->type = Type::tvoid; // ambiguous type?
- }
- else
- {
- exp->type = exp->var->type;
- if (!exp->type && global.errors)
- {
- // var is goofed up, just return 0
- return setError();
- }
- assert(exp->type);
-
- if (t1->ty == Tpointer)
- t1 = t1->nextOf();
-
- exp->type = exp->type->addMod(t1->mod);
-
- Dsymbol *vparent = exp->var->toParent();
- AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL;
-
- if (Expression *e1x = getRightThis(exp->loc, sc, ad, exp->e1, exp->var, 1))
- exp->e1 = e1x;
- else
- {
- /* Later checkRightThis will report correct error for invalid field variable access.
- */
- Expression *e = new VarExp(exp->loc, exp->var);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- checkAccess(exp->loc, sc, exp->e1, exp->var);
-
- VarDeclaration *v = exp->var->isVarDeclaration();
- if (v && (v->isDataseg() || (v->storage_class & STCmanifest)))
- {
- Expression *e = expandVar(WANTvalue, v);
- if (e)
- {
- result = e;
- return;
- }
- }
-
- if (v && v->isDataseg()) // fix bugzilla 8238
- {
- // (e1, v)
- checkAccess(exp->loc, sc, exp->e1, v);
- Expression *e = new VarExp(exp->loc, v);
- e = new CommaExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
-
- //printf("-DotVarExp::semantic('%s')\n", exp->toChars());
- result = exp;
- }
-
- void visit(DotTemplateInstanceExp *exp)
- {
- // Indicate we need to resolve by UFCS.
- Expression *e = semanticY(exp, sc, 1);
- if (!e)
- e = resolveUFCSProperties(sc, exp);
- result = e;
- }
-
- void visit(DelegateExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- e->e1 = expressionSemantic(e->e1, sc);
- e->type = new TypeDelegate(e->func->type);
- e->type = typeSemantic(e->type, e->loc, sc);
- FuncDeclaration *f = e->func->toAliasFunc();
- AggregateDeclaration *ad = f->toParent()->isAggregateDeclaration();
- if (f->needThis())
- e->e1 = getRightThis(e->loc, sc, ad, e->e1, f);
- if (f->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)f->type;
- if (!MODmethodConv(e->e1->type->mod, f->type->mod))
- {
- OutBuffer thisBuf, funcBuf;
- MODMatchToBuffer(&thisBuf, e->e1->type->mod, tf->mod);
- MODMatchToBuffer(&funcBuf, tf->mod, e->e1->type->mod);
- e->error("%smethod %s is not callable using a %s%s",
- funcBuf.peekChars(), f->toPrettyChars(), thisBuf.peekChars(), e->e1->toChars());
- return setError();
- }
- }
- if (ad && ad->isClassDeclaration() && ad->type != e->e1->type)
- {
- // A downcast is required for interfaces, see Bugzilla 3706
- e->e1 = new CastExp(e->loc, e->e1, ad->type);
- e->e1 = expressionSemantic(e->e1, sc);
- }
- result = e;
- }
-
- void visit(DotTypeExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *e = unaSemantic(exp, sc))
- {
- result = e;
- return;
- }
-
- exp->type = exp->sym->getType()->addMod(exp->e1->type->mod);
- result = exp;
- }
-
- void visit(CallExp *exp)
- {
- if (exp->type)
- {
- result = exp; // semantic() already run
- return;
- }
-
- Type *t1;
- Objects *tiargs = NULL; // initial list of template arguments
- Expression *ethis = NULL;
- Type *tthis = NULL;
- Expression *e1org = exp->e1;
-
- if (exp->e1->op == TOKcomma)
- {
- /* Rewrite (a,b)(args) as (a,(b(args)))
- */
- CommaExp *ce = (CommaExp *)exp->e1;
- exp->e1 = ce->e2;
- ce->e2 = exp;
- result = expressionSemantic(ce, sc);
- return;
- }
-
- if (exp->e1->op == TOKdelegate)
- {
- DelegateExp *de = (DelegateExp *)exp->e1;
- exp->e1 = new DotVarExp(de->loc, de->e1, de->func, de->hasOverloads);
- result = expressionSemantic(exp, sc);
- return;
- }
-
- if (exp->e1->op == TOKfunction)
- {
- if (arrayExpressionSemantic(exp->arguments, sc) ||
- preFunctionParameters(sc, exp->arguments))
- {
- return setError();
- }
-
- // Run e1 semantic even if arguments have any errors
- FuncExp *fe = (FuncExp *)exp->e1;
- exp->e1 = callExpSemantic(fe, sc, exp->arguments);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- }
-
- if (Expression *ex = resolveUFCS(sc, exp))
- {
- result = ex;
- return;
- }
-
- /* This recognizes:
- * foo!(tiargs)(funcargs)
- */
- if (exp->e1->op == TOKscope)
- {
- ScopeExp *se = (ScopeExp *)exp->e1;
- TemplateInstance *ti = se->sds->isTemplateInstance();
- if (ti)
- {
- /* Attempt to instantiate ti. If that works, go with it.
- * If not, go with partial explicit specialization.
- */
- WithScopeSymbol *withsym;
- if (!ti->findTempDecl(sc, &withsym) ||
- !ti->semanticTiargs(sc))
- {
- return setError();
- }
- if (withsym && withsym->withstate->wthis)
- {
- exp->e1 = new VarExp(exp->e1->loc, withsym->withstate->wthis);
- exp->e1 = new DotTemplateInstanceExp(exp->e1->loc, exp->e1, ti);
- goto Ldotti;
- }
- if (ti->needsTypeInference(sc, 1))
- {
- /* Go with partial explicit specialization
- */
- tiargs = ti->tiargs;
- assert(ti->tempdecl);
- if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
- exp->e1 = new TemplateExp(exp->loc, td);
- else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
- exp->e1 = new VarExp(exp->loc, od);
- else
- exp->e1 = new OverExp(exp->loc, ti->tempdecl->isOverloadSet());
- }
- else
- {
- Expression *e1x = expressionSemantic(exp->e1, sc);
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- exp->e1 = e1x;
- }
- }
- }
-
- /* This recognizes:
- * expr.foo!(tiargs)(funcargs)
- */
- Ldotti:
- if (exp->e1->op == TOKdotti && !exp->e1->type)
- {
- DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)exp->e1;
- TemplateInstance *ti = se->ti;
- {
- /* Attempt to instantiate ti. If that works, go with it.
- * If not, go with partial explicit specialization.
- */
- if (!se->findTempDecl(sc) ||
- !ti->semanticTiargs(sc))
- {
- return setError();
- }
- if (ti->needsTypeInference(sc, 1))
- {
- /* Go with partial explicit specialization
- */
- tiargs = ti->tiargs;
- assert(ti->tempdecl);
- if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
- exp->e1 = new DotTemplateExp(exp->loc, se->e1, td);
- else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
- {
- exp->e1 = new DotVarExp(exp->loc, se->e1, od, true);
- }
- else
- exp->e1 = new DotExp(exp->loc, se->e1, new OverExp(exp->loc, ti->tempdecl->isOverloadSet()));
- }
- else
- {
- Expression *e1x = expressionSemantic(exp->e1, sc);
- if (e1x->op == TOKerror)
- {
- result =e1x;
- return;
- }
- exp->e1 = e1x;
- }
- }
- }
-
- Lagain:
- //printf("Lagain: %s\n", exp->toChars());
- exp->f = NULL;
- if (exp->e1->op == TOKthis || exp->e1->op == TOKsuper)
- {
- // semantic() run later for these
- }
- else
- {
- if (exp->e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)exp->e1;
- exp->e1 = expressionSemantic(die, sc);
- /* Look for e1 having been rewritten to expr.opDispatch!(string)
- * We handle such earlier, so go back.
- * Note that in the rewrite, we carefully did not run semantic() on e1
- */
- if (exp->e1->op == TOKdotti && !exp->e1->type)
- {
- goto Ldotti;
- }
- }
- else
- {
- static int nest;
- if (++nest > global.recursionLimit)
- {
- exp->error("recursive evaluation of %s", exp->toChars());
- --nest;
- return setError();
- }
- Expression *ex = unaSemantic(exp, sc);
- --nest;
- if (ex)
- {
- result = ex;
- return;
- }
- }
-
- /* Look for e1 being a lazy parameter
- */
- if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
- if (ve->var->storage_class & STClazy)
- {
- // lazy paramaters can be called without violating purity and safety
- Type *tw = ve->var->type;
- Type *tc = ve->var->type->substWildTo(MODconst);
- TypeFunction *tf = new TypeFunction(ParameterList(), tc, LINKd, STCsafe | STCpure);
- (tf = (TypeFunction *)typeSemantic(tf, exp->loc, sc))->next = tw; // hack for bug7757
- TypeDelegate *t = new TypeDelegate(tf);
- ve->type = typeSemantic(t, exp->loc, sc);
- }
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && ve->checkPurity(sc, v))
- return setError();
- }
-
- if (exp->e1->op == TOKsymoff && ((SymOffExp *)exp->e1)->hasOverloads)
- {
- SymOffExp *se = (SymOffExp *)exp->e1;
- exp->e1 = new VarExp(se->loc, se->var, true);
- exp->e1 = expressionSemantic(exp->e1, sc);
- }
- else if (exp->e1->op == TOKdot)
- {
- DotExp *de = (DotExp *) exp->e1;
-
- if (de->e2->op == TOKoverloadset)
- {
- ethis = de->e1;
- tthis = de->e1->type;
- exp->e1 = de->e2;
- }
- }
- else if (exp->e1->op == TOKstar && exp->e1->type->ty == Tfunction)
- {
- // Rewrite (*fp)(arguments) to fp(arguments)
- exp->e1 = ((PtrExp *)exp->e1)->e1;
- }
- }
-
- t1 = exp->e1->type ? exp->e1->type->toBasetype() : NULL;
-
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (arrayExpressionSemantic(exp->arguments, sc) ||
- preFunctionParameters(sc, exp->arguments))
- {
- return setError();
- }
-
- // Check for call operator overload
- if (t1)
- {
- if (t1->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)t1)->sym;
- sd->size(exp->loc); // Resolve forward references to construct object
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
-
- // First look for constructor
- if (exp->e1->op == TOKtype && sd->ctor)
- {
- if (!sd->noDefaultCtor && !(exp->arguments && exp->arguments->length))
- goto Lx;
-
- StructLiteralExp *sle = new StructLiteralExp(exp->loc, sd, NULL, exp->e1->type);
- if (!sd->fill(exp->loc, sle->elements, true))
- return setError();
- if (checkFrameAccess(exp->loc, sc, sd, sle->elements->length))
- return setError();
- // Bugzilla 14556: Set concrete type to avoid further redundant semantic().
- sle->type = exp->e1->type;
-
- /* Constructor takes a mutable object, so don't use
- * the immutable initializer symbol.
- */
- sle->useStaticInit = false;
-
- Expression *e = sle;
- if (CtorDeclaration *cf = sd->ctor->isCtorDeclaration())
- {
- e = new DotVarExp(exp->loc, e, cf, true);
- }
- else if (TemplateDeclaration *td = sd->ctor->isTemplateDeclaration())
- {
- e = new DotTemplateExp(exp->loc, e, td);
- }
- else if (OverloadSet *os = sd->ctor->isOverloadSet())
- {
- e = new DotExp(exp->loc, e, new OverExp(exp->loc, os));
- }
- else
- assert(0);
- e = new CallExp(exp->loc, e, exp->arguments);
- result = expressionSemantic(e, sc);
- return;
- }
- // No constructor, look for overload of opCall
- if (search_function(sd, Id::call))
- goto L1; // overload of opCall, therefore it's a call
-
- if (exp->e1->op != TOKtype)
- {
- if (sd->aliasthis && exp->e1->type != exp->att1)
- {
- if (!exp->att1 && exp->e1->type->checkAliasThisRec())
- exp->att1 = exp->e1->type;
- exp->e1 = resolveAliasThis(sc, exp->e1);
- goto Lagain;
- }
- exp->error("%s %s does not overload ()", sd->kind(), sd->toChars());
- return setError();
- }
-
- /* It's a struct literal
- */
- Lx:
- Expression *e = new StructLiteralExp(exp->loc, sd, exp->arguments, exp->e1->type);
- result = expressionSemantic(e, sc);
- return;
- }
- else if (t1->ty == Tclass)
- {
- L1:
- // Rewrite as e1.call(arguments)
- Expression *e = new DotIdExp(exp->loc, exp->e1, Id::call);
- e = new CallExp(exp->loc, e, exp->arguments);
- result = expressionSemantic(e, sc);
- return;
- }
- else if (exp->e1->op == TOKtype && t1->isscalar())
- {
- Expression *e;
-
- // Make sure to use the the enum type itself rather than its
- // base type (see bugzilla 16346)
- if (exp->e1->type->ty == Tenum)
- {
- t1 = exp->e1->type;
- }
-
- if (!exp->arguments || exp->arguments->length == 0)
- {
- e = t1->defaultInitLiteral(exp->loc);
- }
- else if (exp->arguments->length == 1)
- {
- e = (*exp->arguments)[0];
- e = e->implicitCastTo(sc, t1);
- e = new CastExp(exp->loc, e, t1);
- }
- else
- {
- exp->error("more than one argument for construction of %s", t1->toChars());
- e = new ErrorExp();
- }
- result = expressionSemantic(e, sc);
- return;
- }
- }
-
- if ((exp->e1->op == TOKdotvar && t1->ty == Tfunction) ||
- exp->e1->op == TOKdottd)
- {
- UnaExp *ue = (UnaExp *)(exp->e1);
-
- Expression *ue1 = ue->e1;
- Expression *ue1old = ue1; // need for 'right this' check
- VarDeclaration *v;
- if (ue1->op == TOKvar &&
- (v = ((VarExp *)ue1)->var->isVarDeclaration()) != NULL &&
- v->needThis())
- {
- ue->e1 = new TypeExp(ue1->loc, ue1->type);
- ue1 = NULL;
- }
-
- DotVarExp *dve;
- DotTemplateExp *dte;
- Dsymbol *s;
- if (exp->e1->op == TOKdotvar)
- {
- dve = (DotVarExp *)(exp->e1);
- dte = NULL;
- s = dve->var;
- tiargs = NULL;
- }
- else
- {
- dve = NULL;
- dte = (DotTemplateExp *)(exp->e1);
- s = dte->td;
- }
-
- // Do overload resolution
- exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, ue1 ? ue1->type : NULL, exp->arguments);
- if (!exp->f || exp->f->errors || exp->f->type->ty == Terror)
- return setError();
- if (exp->f->interfaceVirtual)
- {
- /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
- */
- BaseClass *b = exp->f->interfaceVirtual;
- ClassDeclaration *ad2 = b->sym;
- ue->e1 = ue->e1->castTo(sc, ad2->type->addMod(ue->e1->type->mod));
- ue->e1 = expressionSemantic(ue->e1, sc);
- ue1 = ue->e1;
- int vi = exp->f->findVtblIndex((Dsymbols*)&ad2->vtbl, (int)ad2->vtbl.length);
- assert(vi >= 0);
- exp->f = ad2->vtbl[vi]->isFuncDeclaration();
- assert(exp->f);
- }
- if (exp->f->needThis())
- {
- AggregateDeclaration *ad = exp->f->toParent2()->isAggregateDeclaration();
- ue->e1 = getRightThis(exp->loc, sc, ad, ue->e1, exp->f);
- if (ue->e1->op == TOKerror)
- {
- result = ue->e1;
- return;
- }
- ethis = ue->e1;
- tthis = ue->e1->type;
- if (!(exp->f->type->ty == Tfunction && ((TypeFunction *)exp->f->type)->isscope))
- {
- if (global.params.vsafe && checkParamArgumentEscape(sc, exp->f, Id::This, ethis, false))
- return setError();
- }
- }
-
- /* Cannot call public functions from inside invariant
- * (because then the invariant would have infinite recursion)
- */
- if (sc->func && sc->func->isInvariantDeclaration() &&
- ue->e1->op == TOKthis &&
- exp->f->addPostInvariant()
- )
- {
- exp->error("cannot call public/export function %s from invariant", exp->f->toChars());
- return setError();
- }
-
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- checkAccess(exp->loc, sc, ue->e1, exp->f);
- if (!exp->f->needThis())
- {
- exp->e1 = Expression::combine(ue->e1, new VarExp(exp->loc, exp->f, false));
- }
- else
- {
- if (ue1old->checkRightThis(sc))
- return setError();
- if (exp->e1->op == TOKdotvar)
- {
- dve->var = exp->f;
- exp->e1->type = exp->f->type;
- }
- else
- {
- exp->e1 = new DotVarExp(exp->loc, dte->e1, exp->f, false);
- exp->e1 = expressionSemantic(exp->e1, sc);
- if (exp->e1->op == TOKerror)
- return setError();
- ue = (UnaExp *)exp->e1;
- }
-
- // See if we need to adjust the 'this' pointer
- AggregateDeclaration *ad = exp->f->isThis();
- ClassDeclaration *cd = ue->e1->type->isClassHandle();
- if (ad && cd && ad->isClassDeclaration())
- {
- if (ue->e1->op == TOKdottype)
- {
- ue->e1 = ((DotTypeExp *)ue->e1)->e1;
- exp->directcall = true;
- }
- else if (ue->e1->op == TOKsuper)
- exp->directcall = true;
- else if ((cd->storage_class & STCfinal) != 0) // Bugzilla 14211
- exp->directcall = true;
-
- if (ad != cd)
- {
- ue->e1 = ue->e1->castTo(sc, ad->type->addMod(ue->e1->type->mod));
- ue->e1 = expressionSemantic(ue->e1, sc);
- }
- }
- }
- // If we've got a pointer to a function then deference it
- // https://issues.dlang.org/show_bug.cgi?id=16483
- if (exp->e1->type->ty == Tpointer && exp->e1->type->nextOf()->ty == Tfunction)
- {
- Expression *e = new PtrExp(exp->loc, exp->e1);
- e->type = exp->e1->type->nextOf();
- exp->e1 = e;
- }
- t1 = exp->e1->type;
- }
- else if (exp->e1->op == TOKsuper)
- {
- // Base class constructor call
- AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
- ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
- if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration())
- {
- exp->error("super class constructor call must be in a constructor");
- return setError();
- }
- if (!cd->baseClass->ctor)
- {
- exp->error("no super class constructor for %s", cd->baseClass->toChars());
- return setError();
- }
-
- if (!sc->intypeof && !(sc->callSuper & CSXhalt))
- {
- if (sc->noctor || sc->callSuper & CSXlabel)
- exp->error("constructor calls not allowed in loops or after labels");
- if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
- exp->error("multiple constructor calls");
- if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
- exp->error("an earlier return statement skips constructor");
- sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
- }
-
- tthis = cd->type->addMod(sc->func->type->mod);
- if (OverloadSet *os = cd->baseClass->ctor->isOverloadSet())
- exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
- else
- exp->f = resolveFuncCall(exp->loc, sc, cd->baseClass->ctor, NULL, tthis, exp->arguments, 0);
- if (!exp->f || exp->f->errors)
- return setError();
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- checkAccess(exp->loc, sc, NULL, exp->f);
-
- exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
- exp->e1 = expressionSemantic(exp->e1, sc);
- t1 = exp->e1->type;
- }
- else if (exp->e1->op == TOKthis)
- {
- // same class constructor call
- AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
- if (!ad || !sc->func->isCtorDeclaration())
- {
- exp->error("constructor call must be in a constructor");
- return setError();
- }
-
- // https://issues.dlang.org/show_bug.cgi?id=18719
- // If `exp` is a call expression to another constructor
- // then it means that all struct/class fields will be
- // initialized after this call.
- for (size_t i = 0; i < sc->fieldinit_dim; i++)
- sc->fieldinit[i] |= CSXthis_ctor;
-
- if (!sc->intypeof && !(sc->callSuper & CSXhalt))
- {
- if (sc->noctor || sc->callSuper & CSXlabel)
- exp->error("constructor calls not allowed in loops or after labels");
- if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
- exp->error("multiple constructor calls");
- if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
- exp->error("an earlier return statement skips constructor");
- sc->callSuper |= CSXany_ctor | CSXthis_ctor;
- }
-
- tthis = ad->type->addMod(sc->func->type->mod);
- if (OverloadSet *os = ad->ctor->isOverloadSet())
- exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
- else
- exp->f = resolveFuncCall(exp->loc, sc, ad->ctor, NULL, tthis, exp->arguments, 0);
- if (!exp->f || exp->f->errors)
- return setError();
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- //checkAccess(exp->loc, sc, NULL, exp->f); // necessary?
-
- exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
- exp->e1 = expressionSemantic(exp->e1, sc);
- t1 = exp->e1->type;
-
- // BUG: this should really be done by checking the static
- // call graph
- if (exp->f == sc->func)
- {
- exp->error("cyclic constructor call");
- return setError();
- }
- }
- else if (exp->e1->op == TOKoverloadset)
- {
- OverloadSet *os = ((OverExp *)exp->e1)->vars;
- exp->f = resolveOverloadSet(exp->loc, sc, os, tiargs, tthis, exp->arguments);
- if (!exp->f)
- return setError();
- if (ethis)
- exp->e1 = new DotVarExp(exp->loc, ethis, exp->f, false);
- else
- exp->e1 = new VarExp(exp->loc, exp->f, false);
- goto Lagain;
- }
- else if (!t1)
- {
- exp->error("function expected before (), not `%s`", exp->e1->toChars());
- return setError();
- }
- else if (t1->ty == Terror)
- {
- return setError();
- }
- else if (t1->ty != Tfunction)
- {
- TypeFunction *tf;
- const char *p;
- Dsymbol *s;
- exp->f = NULL;
- if (exp->e1->op == TOKfunction)
- {
- // function literal that direct called is always inferred.
- assert(((FuncExp *)exp->e1)->fd);
- exp->f = ((FuncExp *)exp->e1)->fd;
- tf = (TypeFunction *)exp->f->type;
- p = "function literal";
- }
- else if (t1->ty == Tdelegate)
- {
- TypeDelegate *td = (TypeDelegate *)t1;
- assert(td->next->ty == Tfunction);
- tf = (TypeFunction *)(td->next);
- p = "delegate";
- }
- else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction)
- {
- tf = (TypeFunction *)(((TypePointer *)t1)->next);
- p = "function pointer";
- }
- else if (exp->e1->op == TOKdotvar &&
- ((DotVarExp *)exp->e1)->var->isOverDeclaration())
- {
- DotVarExp *dve = (DotVarExp *)exp->e1;
- exp->f = resolveFuncCall(exp->loc, sc, dve->var, tiargs, dve->e1->type, exp->arguments, 2);
- if (!exp->f)
- return setError();
- if (exp->f->needThis())
- {
- dve->var = exp->f;
- dve->type = exp->f->type;
- dve->hasOverloads = false;
- goto Lagain;
- }
- exp->e1 = new VarExp(dve->loc, exp->f, false);
- Expression *e = new CommaExp(exp->loc, dve->e1, exp);
- result = expressionSemantic(e, sc);
- return;
- }
- else if (exp->e1->op == TOKvar &&
- ((VarExp *)exp->e1)->var->isOverDeclaration())
- {
- s = ((VarExp *)exp->e1)->var;
- goto L2;
- }
- else if (exp->e1->op == TOKtemplate)
- {
- s = ((TemplateExp *)exp->e1)->td;
- L2:
- exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, NULL, exp->arguments);
- if (!exp->f || exp->f->errors)
- return setError();
- if (exp->f->needThis())
- {
- if (hasThis(sc))
- {
- // Supply an implicit 'this', as in
- // this.ident
- Expression *ex = new ThisExp(exp->loc);
- ex = expressionSemantic(ex, sc);
- exp->e1 = new DotVarExp(exp->loc, ex, exp->f, false);
- goto Lagain;
- }
- else if (isNeedThisScope(sc, exp->f))
- {
- exp->error("need `this` for `%s` of type `%s`", exp->f->toChars(), exp->f->type->toChars());
- return setError();
- }
- }
- exp->e1 = new VarExp(exp->e1->loc, exp->f, false);
- goto Lagain;
- }
- else
- {
- exp->error("function expected before (), not %s of type %s", exp->e1->toChars(), exp->e1->type->toChars());
- return setError();
- }
-
- const char *failMessage = NULL;
- if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
- {
- OutBuffer buf;
-
- buf.writeByte('(');
- argExpTypesToCBuffer(&buf, exp->arguments);
- buf.writeByte(')');
- if (tthis)
- tthis->modToBuffer(&buf);
-
- //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
- ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
- p, exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
- buf.peekChars());
- if (failMessage)
- errorSupplemental(exp->loc, failMessage);
- return setError();
- }
-
- // Purity and safety check should run after testing arguments matching
- if (exp->f)
- {
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- if (exp->f->checkNestedReference(sc, exp->loc))
- return setError();
- }
- else if (sc->func && sc->intypeof != 1 && !(sc->flags & SCOPEctfe))
- {
- bool err = false;
- if (!tf->purity && !(sc->flags & SCOPEdebug) && sc->func->setImpure())
- {
- exp->error("pure %s `%s` cannot call impure %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
- err = true;
- }
- if (!tf->isnogc && sc->func->setGC())
- {
- exp->error("@nogc %s `%s` cannot call non-@nogc %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
- err = true;
- }
- if (tf->trust <= TRUSTsystem && sc->func->setUnsafe())
- {
- exp->error("@safe %s `%s` cannot call @system %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
- err = true;
- }
- if (err)
- return setError();
- }
-
- if (t1->ty == Tpointer)
- {
- Expression *e = new PtrExp(exp->loc, exp->e1);
- e->type = tf;
- exp->e1 = e;
- }
- t1 = tf;
- }
- else if (exp->e1->op == TOKvar)
- {
- // Do overload resolution
- VarExp *ve = (VarExp *)exp->e1;
-
- exp->f = ve->var->isFuncDeclaration();
- assert(exp->f);
- tiargs = NULL;
-
- if (exp->f->overnext)
- exp->f = resolveFuncCall(exp->loc, sc, exp->f, tiargs, NULL, exp->arguments, 2);
- else
- {
- exp->f = exp->f->toAliasFunc();
- TypeFunction *tf = (TypeFunction *)exp->f->type;
- const char *failMessage = NULL;
- if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
- {
- OutBuffer buf;
-
- buf.writeByte('(');
- argExpTypesToCBuffer(&buf, exp->arguments);
- buf.writeByte(')');
-
- //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
- ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
- exp->f->kind(), exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
- buf.peekChars());
- if (failMessage)
- errorSupplemental(exp->loc, failMessage);
- exp->f = NULL;
- }
- }
- if (!exp->f || exp->f->errors)
- return setError();
-
- if (exp->f->needThis())
- {
- // Change the ancestor lambdas to delegate before hasThis(sc) call.
- if (exp->f->checkNestedReference(sc, exp->loc))
- return setError();
-
- if (hasThis(sc))
- {
- // Supply an implicit 'this', as in
- // this.ident
-
- Expression *ex = new ThisExp(exp->loc);
- ex = expressionSemantic(ex, sc);
- exp->e1 = new DotVarExp(exp->loc, ex, ve->var);
- // Note: we cannot use f directly, because further overload resolution
- // through the supplied 'this' may cause different result.
- goto Lagain;
- }
- else if (isNeedThisScope(sc, exp->f))
- {
- exp->error("need `this` for `%s` of type `%s`", exp->f->toChars(), exp->f->type->toChars());
- return setError();
- }
- }
-
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- checkAccess(exp->loc, sc, NULL, exp->f);
- if (exp->f->checkNestedReference(sc, exp->loc))
- return setError();
-
- ethis = NULL;
- tthis = NULL;
-
- if (ve->hasOverloads)
- {
- exp->e1 = new VarExp(ve->loc, exp->f, false);
- exp->e1->type = exp->f->type;
- }
- t1 = exp->f->type;
- }
- assert(t1->ty == Tfunction);
-
- Expression *argprefix;
- if (!exp->arguments)
- exp->arguments = new Expressions();
- if (functionParameters(exp->loc, sc, (TypeFunction *)(t1), tthis, exp->arguments, exp->f, &exp->type, &argprefix))
- return setError();
-
- if (!exp->type)
- {
- exp->e1 = e1org; // Bugzilla 10922, avoid recursive expression printing
- exp->error("forward reference to inferred return type of function call `%s`", exp->toChars());
- return setError();
- }
-
- if (exp->f && exp->f->tintro)
- {
- Type *t = exp->type;
- int offset = 0;
- TypeFunction *tf = (TypeFunction *)exp->f->tintro;
-
- if (tf->next->isBaseOf(t, &offset) && offset)
- {
- exp->type = tf->next;
- result = Expression::combine(argprefix, exp->castTo(sc, t));
- return;
- }
- }
-
- // Handle the case of a direct lambda call
- if (exp->f && exp->f->isFuncLiteralDeclaration() &&
- sc->func && !sc->intypeof)
- {
- exp->f->tookAddressOf = 0;
- }
-
- result = Expression::combine(argprefix, exp);
- }
-
- void visit(AddrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- int wasCond = exp->e1->op == TOKquestion;
- if (exp->e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)exp->e1;
- TemplateInstance *ti = dti->ti;
- {
- //assert(ti->needsTypeInference(sc));
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors) // if template failed to expand
- return setError();
- Dsymbol *s = ti->toAlias();
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- exp->e1 = new DotVarExp(exp->e1->loc, dti->e1, f);
- exp->e1 = expressionSemantic(exp->e1, sc);
- }
- }
- }
- else if (exp->e1->op == TOKscope)
- {
- TemplateInstance *ti = ((ScopeExp *)exp->e1)->sds->isTemplateInstance();
- if (ti)
- {
- //assert(ti->needsTypeInference(sc));
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors) // if template failed to expand
- return setError();
- Dsymbol *s = ti->toAlias();
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- exp->e1 = new VarExp(exp->e1->loc, f);
- exp->e1 = expressionSemantic(exp->e1, sc);
- }
- }
- }
- exp->e1 = exp->e1->toLvalue(sc, NULL);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- if (!exp->e1->type)
- {
- exp->error("cannot take address of %s", exp->e1->toChars());
- return setError();
- }
-
- bool hasOverloads = false;
- if (FuncDeclaration *f = isFuncAddress(exp, &hasOverloads))
- {
- if (!hasOverloads && f->checkForwardRef(exp->loc))
- return setError();
- }
- else if (!exp->e1->type->deco)
- {
- if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
- Declaration *d = ve->var;
- exp->error("forward reference to %s %s", d->kind(), d->toChars());
- }
- else
- exp->error("forward reference to %s", exp->e1->toChars());
- return setError();
- }
-
- exp->type = exp->e1->type->pointerTo();
-
- // See if this should really be a delegate
- if (exp->e1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)exp->e1;
- FuncDeclaration *f = dve->var->isFuncDeclaration();
- if (f)
- {
- f = f->toAliasFunc(); // FIXME, should see overloads - Bugzilla 1983
- if (!dve->hasOverloads)
- f->tookAddressOf++;
-
- Expression *e;
- if (f->needThis())
- e = new DelegateExp(exp->loc, dve->e1, f, dve->hasOverloads);
- else // It is a function pointer. Convert &v.f() --> (v, &V.f())
- e = new CommaExp(exp->loc, dve->e1, new AddrExp(exp->loc, new VarExp(exp->loc, f, dve->hasOverloads)));
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- // Look for misaligned pointer in @safe mode
- if (checkUnsafeAccess(sc, dve, !exp->type->isMutable(), true))
- return setError();
-
- if (dve->e1->op == TOKvar && global.params.vsafe)
- {
- VarExp *ve = (VarExp *)dve->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- else if ((dve->e1->op == TOKthis || dve->e1->op == TOKsuper) && global.params.vsafe)
- {
- ThisExp *ve = (ThisExp *)dve->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && v->storage_class & STCref)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- }
- else if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
-
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
-
- ve->checkPurity(sc, v);
- }
-
- FuncDeclaration *f = ve->var->isFuncDeclaration();
- if (f)
- {
- /* Because nested functions cannot be overloaded,
- * mark here that we took its address because castTo()
- * may not be called with an exact match.
- */
- if (!ve->hasOverloads || f->isNested())
- f->tookAddressOf++;
- if (f->isNested())
- {
- if (f->isFuncLiteralDeclaration())
- {
- if (!f->FuncDeclaration::isNested())
- {
- /* Supply a 'null' for a this pointer if no this is available
- */
- Expression *e = new DelegateExp(exp->loc, new NullExp(exp->loc, Type::tnull), f, ve->hasOverloads);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- Expression *e = new DelegateExp(exp->loc, exp->e1, f, ve->hasOverloads);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (f->needThis())
- {
- if (hasThis(sc))
- {
- /* Should probably supply 'this' after overload resolution,
- * not before.
- */
- Expression *ethis = new ThisExp(exp->loc);
- Expression *e = new DelegateExp(exp->loc, ethis, f, ve->hasOverloads);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (sc->func && !sc->intypeof)
- {
- if (sc->func->setUnsafe())
- {
- exp->error("`this` reference necessary to take address of member %s in @safe function %s",
- f->toChars(), sc->func->toChars());
- }
- }
- }
- }
- }
- else if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && global.params.vsafe)
- {
- ThisExp *ve = (ThisExp *)exp->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- else if (exp->e1->op == TOKcall)
- {
- CallExp *ce = (CallExp *)exp->e1;
- if (ce->e1->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)ce->e1->type;
- if (tf->isref && sc->func && !sc->intypeof && sc->func->setUnsafe())
- {
- exp->error("cannot take address of ref return of %s() in @safe function %s",
- ce->e1->toChars(), sc->func->toChars());
- }
- }
- }
- else if (exp->e1->op == TOKindex)
- {
- /* For:
- * int[3] a;
- * &a[i]
- * check 'a' the same as for a regular variable
- */
- IndexExp *ei = (IndexExp *)exp->e1;
- Type *tyi = ei->e1->type->toBasetype();
- if (tyi->ty == Tsarray && ei->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)ei->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
-
- ve->checkPurity(sc, v);
- }
- }
- }
- else if (wasCond)
- {
- /* a ? b : c was transformed to *(a ? &b : &c), but we still
- * need to do safety checks
- */
- assert(exp->e1->op == TOKstar);
- PtrExp *pe = (PtrExp *)exp->e1;
- assert(pe->e1->op == TOKquestion);
- CondExp *ce = (CondExp *)pe->e1;
- assert(ce->e1->op == TOKaddress);
- assert(ce->e2->op == TOKaddress);
-
- // Re-run semantic on the address expressions only
- ce->e1->type = NULL;
- ce->e1 = expressionSemantic(ce->e1, sc);
- ce->e2->type = NULL;
- ce->e2 = expressionSemantic(ce->e2, sc);
- }
-
- result = exp->optimize(WANTvalue);
- }
-
- void visit(PtrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *tb = exp->e1->type->toBasetype();
- switch (tb->ty)
- {
- case Tpointer:
- exp->type = ((TypePointer *)tb)->next;
- break;
-
- case Tsarray:
- case Tarray:
- exp->error("using * on an array is no longer supported; use *(%s).ptr instead", exp->e1->toChars());
- exp->type = ((TypeArray *)tb)->next;
- exp->e1 = exp->e1->castTo(sc, exp->type->pointerTo());
- break;
-
- case Tnull:
- exp->type = Type::tnoreturn; // typeof(*null) is bottom type
- break;
-
- default:
- exp->error("can only * a pointer, not a `%s`", exp->e1->type->toChars());
- /* fall through */
-
- case Terror:
- return setError();
- }
- if (exp->checkValue())
- return setError();
-
- result = exp;
- }
-
- void visit(NegExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- exp->type = exp->e1->type;
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp->e1))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->e1->checkNoBool())
- return setError();
- if (exp->e1->checkArithmetic())
- return setError();
-
- result = exp;
- }
-
- void visit(UAddExp *exp)
- {
- assert(!exp->type);
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->e1->checkNoBool())
- return setError();
- if (exp->e1->checkArithmetic())
- return setError();
-
- result = exp->e1;
- }
-
- void visit(ComExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- exp->type = exp->e1->type;
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp->e1))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->e1->checkNoBool())
- return setError();
- if (exp->e1->checkIntegral())
- return setError();
-
- result = exp;
- }
-
- void visit(NotExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- setNoderefOperand(e);
-
- // Note there is no operator overload
- if (Expression *ex = unaSemantic(e, sc))
- {
- result = ex;
- return;
- }
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e->e1->op == TOKtype)
- e->e1 = resolveAliasThis(sc, e->e1);
-
- e->e1 = resolveProperties(sc, e->e1);
- e->e1 = e->e1->toBoolean(sc);
- if (e->e1->type == Type::terror)
- {
- result = e->e1;
- return;
- }
-
- if (!target.isVectorOpSupported(e->e1->type->toBasetype(), e->op))
- {
- result = e->incompatibleTypes();
- return;
- }
- // Bugzilla 13910: Today NotExp can take an array as its operand.
- if (checkNonAssignmentArrayOp(e->e1))
- return setError();
-
- e->type = Type::tbool;
- result = e;
- }
-
- void visit(DeleteExp *exp)
- {
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- exp->e1 = resolveProperties(sc, exp->e1);
- exp->e1 = exp->e1->modifiableLvalue(sc, NULL);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- exp->type = Type::tvoid;
-
- AggregateDeclaration *ad = NULL;
- Type *tb = exp->e1->type->toBasetype();
- switch (tb->ty)
- { case Tclass:
- {
- ClassDeclaration *cd = ((TypeClass *)tb)->sym;
-
- if (cd->isCOMinterface())
- { /* Because COM classes are deleted by IUnknown.Release()
- */
- exp->error("cannot delete instance of COM interface %s", cd->toChars());
- return setError();
- }
-
- ad = cd;
- break;
- }
- case Tpointer:
- tb = ((TypePointer *)tb)->next->toBasetype();
- if (tb->ty == Tstruct)
- {
- ad = ((TypeStruct *)tb)->sym;
- FuncDeclaration *f = ad->aggDelete;
- FuncDeclaration *fd = ad->dtor;
-
- if (!f)
- {
- semanticTypeInfo(sc, tb);
- break;
- }
-
- /* Construct:
- * ea = copy e1 to a tmp to do side effects only once
- * eb = call destructor
- * ec = call deallocator
- */
- Expression *ea = NULL;
- Expression *eb = NULL;
- Expression *ec = NULL;
- VarDeclaration *v = NULL;
-
- if (fd && f)
- {
- v = copyToTemp(0, "__tmpea", exp->e1);
- dsymbolSemantic(v, sc);
- ea = new DeclarationExp(exp->loc, v);
- ea->type = v->type;
- }
-
- if (fd)
- {
- Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1;
- e = new DotVarExp(Loc(), e, fd, false);
- eb = new CallExp(exp->loc, e);
- eb = expressionSemantic(eb, sc);
- }
-
- if (f)
- {
- Type *tpv = Type::tvoid->pointerTo();
- Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1->castTo(sc, tpv);
- e = new CallExp(exp->loc, new VarExp(exp->loc, f, false), e);
- ec = expressionSemantic(e, sc);
- }
- ea = Expression::combine(ea, eb);
- ea = Expression::combine(ea, ec);
- assert(ea);
- result = ea;
- return;
- }
- break;
-
- case Tarray:
- {
- Type *tv = tb->nextOf()->baseElemOf();
- if (tv->ty == Tstruct)
- {
- ad = ((TypeStruct *)tv)->sym;
- if (ad->dtor)
- semanticTypeInfo(sc, ad->type);
- }
- break;
- }
- default:
- exp->error("cannot delete type %s", exp->e1->type->toChars());
- return setError();
- }
-
- bool err = false;
- if (ad)
- {
- if (ad->dtor)
- {
- err |= exp->checkPurity(sc, ad->dtor);
- err |= exp->checkSafety(sc, ad->dtor);
- err |= exp->checkNogc(sc, ad->dtor);
- }
- if (ad->aggDelete && tb->ty != Tarray)
- {
- err |= exp->checkPurity(sc, ad->aggDelete);
- err |= exp->checkSafety(sc, ad->aggDelete);
- err |= exp->checkNogc(sc, ad->aggDelete);
- }
- if (err)
- return setError();
- }
-
- if (!sc->intypeof && sc->func &&
- !exp->isRAII &&
- sc->func->setUnsafe())
- {
- exp->error("%s is not @safe but is used in @safe function %s", exp->toChars(), sc->func->toChars());
- err = true;
- }
- if (err)
- return setError();
-
- result = exp;
- }
-
- void visit(CastExp *exp)
- {
- //static int x; assert(++x < 10);
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (exp->to)
- {
- exp->to = typeSemantic(exp->to, exp->loc, sc);
- if (exp->to == Type::terror)
- return setError();
-
- if (!exp->to->hasPointers())
- setNoderefOperand(exp);
-
- // When e1 is a template lambda, this cast may instantiate it with
- // the type 'to'.
- exp->e1 = inferType(exp->e1, exp->to);
- }
-
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e1x = resolveProperties(sc, exp->e1);
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- if (e1x->checkType())
- return setError();
- exp->e1 = e1x;
-
- if (!exp->e1->type)
- {
- exp->error("cannot cast %s", exp->e1->toChars());
- return setError();
- }
-
- if (!exp->to) // Handle cast(const) and cast(immutable), etc.
- {
- exp->to = exp->e1->type->castMod(exp->mod);
- exp->to = typeSemantic(exp->to, exp->loc, sc);
- if (exp->to == Type::terror)
- return setError();
- }
-
- if (exp->to->ty == Ttuple)
- {
- exp->error("cannot cast %s to tuple type %s", exp->e1->toChars(), exp->to->toChars());
- return setError();
- }
- if (exp->e1->type->ty != Tvoid ||
- (exp->e1->op == TOKfunction && exp->to->ty == Tvoid) ||
- exp->e1->op == TOKtype ||
- exp->e1->op == TOKtemplate)
- {
- if (exp->e1->checkValue())
- return setError();
- }
-
- // cast(void) is used to mark e1 as unused, so it is safe
- if (exp->to->ty == Tvoid)
- {
- exp->type = exp->to;
- result = exp;
- return;
- }
-
- if (!exp->to->equals(exp->e1->type) && exp->mod == (unsigned char)~0)
- {
- if (Expression *e = exp->op_overload(sc))
- {
- result = e->implicitCastTo(sc, exp->to);
- return;
- }
- }
-
- Type *t1b = exp->e1->type->toBasetype();
- Type *tob = exp->to->toBasetype();
-
- if (tob->ty == Tstruct && !tob->equals(t1b))
- {
- /* Look to replace:
- * cast(S)t
- * with:
- * S(t)
- */
-
- // Rewrite as to.call(e1)
- Expression *e = new TypeExp(exp->loc, exp->to);
- e = new CallExp(exp->loc, e, exp->e1);
- e = trySemantic(e, sc);
- if (e)
- {
- result = e;
- return;
- }
- }
-
- if (!t1b->equals(tob) && (t1b->ty == Tarray || t1b->ty == Tsarray))
- {
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
- }
-
- // Look for casting to a vector type
- if (tob->ty == Tvector && t1b->ty != Tvector)
- {
- result = new VectorExp(exp->loc, exp->e1, exp->to);
- return;
- }
-
- Expression *ex = exp->e1->castTo(sc, exp->to);
- if (ex->op == TOKerror)
- {
- result = ex;
- return;
- }
-
- // Check for unsafe casts
- if (sc->func && !sc->intypeof &&
- !isSafeCast(ex, t1b, tob) &&
- sc->func->setUnsafe())
- {
- exp->error("cast from %s to %s not allowed in safe code", exp->e1->type->toChars(), exp->to->toChars());
- return setError();
- }
-
- result = ex;
- }
-
- void visit(VectorExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- exp->e1 = expressionSemantic(exp->e1, sc);
- exp->type = typeSemantic(exp->to, exp->loc, sc);
- if (exp->e1->op == TOKerror || exp->type->ty == Terror)
- {
- result = exp->e1;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- assert(tb->ty == Tvector);
- TypeVector *tv = (TypeVector *)tb;
- Type *te = tv->elementType();
- exp->dim = (int)(tv->size(exp->loc) / te->size(exp->loc));
-
- exp->e1 = exp->e1->optimize(WANTvalue);
- bool res = false;
- if (exp->e1->op == TOKarrayliteral)
- {
- for (size_t i = 0; i < exp->dim; i++)
- {
- // Do not stop on first error - check all AST nodes even if error found
- res |= checkVectorElem(exp, ((ArrayLiteralExp *)exp->e1)->getElement(i));
- }
- }
- else if (exp->e1->type->ty == Tvoid)
- res = checkVectorElem(exp, exp->e1);
-
- Expression *e = exp;
- if (res)
- e = new ErrorExp();
- result = e;
- }
-
- void visit(VectorArrayExp *e)
- {
- if (!e->type)
- {
- unaSemantic(e, sc);
- e->e1 = resolveProperties(sc, e->e1);
-
- if (e->e1->op == TOKerror)
- {
- result = e->e1;
- return;
- }
- assert(e->e1->type->ty == Tvector);
- TypeVector *tv = (TypeVector *)e->e1->type;
- e->type = tv->basetype;
- }
- result = e;
- }
-
- void visit(SliceExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- // operator overloading should be handled in ArrayExp already.
-
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- exp->e1 = resolveProperties(sc, exp->e1);
- if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
- {
- if (exp->lwr || exp->upr)
- {
- exp->error("cannot slice type `%s`", exp->e1->toChars());
- return setError();
- }
- Expression *e = new TypeExp(exp->loc, exp->e1->type->arrayOf());
- result = expressionSemantic(e, sc);
- return;
- }
- if (!exp->lwr && !exp->upr)
- {
- if (exp->e1->op == TOKarrayliteral)
- {
- // Convert [a,b,c][] to [a,b,c]
- Type *t1b = exp->e1->type->toBasetype();
- Expression *e = exp->e1;
- if (t1b->ty == Tsarray)
- {
- e = e->copy();
- e->type = t1b->nextOf()->arrayOf();
- }
- result = e;
- return;
- }
- if (exp->e1->op == TOKslice)
- {
- // Convert e[][] to e[]
- SliceExp *se = (SliceExp *)exp->e1;
- if (!se->lwr && !se->upr)
- {
- result = se;
- return;
- }
- }
- if (isArrayOpOperand(exp->e1))
- {
- // Convert (a[]+b[])[] to a[]+b[]
- result = exp->e1;
- return;
- }
- }
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->e1->type->ty == Terror)
- return setError();
-
- Type *t1b = exp->e1->type->toBasetype();
- if (t1b->ty == Tpointer)
- {
- if (((TypePointer *)t1b)->next->ty == Tfunction)
- {
- exp->error("cannot slice function pointer %s", exp->e1->toChars());
- return setError();
- }
- if (!exp->lwr || !exp->upr)
- {
- exp->error("need upper and lower bound to slice pointer");
- return setError();
- }
- if (sc->func && !sc->intypeof && sc->func->setUnsafe())
- {
- exp->error("pointer slicing not allowed in safe functions");
- return setError();
- }
- }
- else if (t1b->ty == Tarray)
- {
- }
- else if (t1b->ty == Tsarray)
- {
- if (!exp->arrayop && global.params.vsafe)
- {
- /* Slicing a static array is like taking the address of it.
- * Perform checks as if e[] was &e
- */
- VarDeclaration *v = NULL;
- if (exp->e1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)exp->e1;
- if (dve->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)dve->e1;
- v = ve->var->isVarDeclaration();
- }
- else if (dve->e1->op == TOKthis || dve->e1->op == TOKsuper)
- {
- ThisExp *ve = (ThisExp *)dve->e1;
- v = ve->var->isVarDeclaration();
- if (v && !(v->storage_class & STCref))
- v = NULL;
- }
- }
- else if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
- v = ve->var->isVarDeclaration();
- }
- else if (exp->e1->op == TOKthis || exp->e1->op == TOKsuper)
- {
- ThisExp *ve = (ThisExp *)exp->e1;
- v = ve->var->isVarDeclaration();
- }
-
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- }
- else if (t1b->ty == Ttuple)
- {
- if (!exp->lwr && !exp->upr)
- {
- result = exp->e1;
- return;
- }
- if (!exp->lwr || !exp->upr)
- {
- exp->error("need upper and lower bound to slice tuple");
- return setError();
- }
- }
- else if (t1b->ty == Tvector)
- {
- // Convert e1 to corresponding static array
- TypeVector *tv1 = (TypeVector *)t1b;
- t1b = tv1->basetype;
- t1b = t1b->castMod(tv1->mod);
- exp->e1->type = t1b;
- }
- else
- {
- exp->error("%s cannot be sliced with []",
- t1b->ty == Tvoid ? exp->e1->toChars() : t1b->toChars());
- return setError();
- }
-
- /* Run semantic on lwr and upr.
- */
- Scope *scx = sc;
- if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
- {
- // Create scope for 'length' variable
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
- sym->loc = exp->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- }
- if (exp->lwr)
- {
- if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->lwr = expressionSemantic(exp->lwr, sc);
- exp->lwr = resolveProperties(sc, exp->lwr);
- if (t1b->ty == Ttuple) sc = sc->endCTFE();
- exp->lwr = exp->lwr->implicitCastTo(sc, Type::tsize_t);
- }
- if (exp->upr)
- {
- if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->upr = expressionSemantic(exp->upr, sc);
- exp->upr = resolveProperties(sc, exp->upr);
- if (t1b->ty == Ttuple) sc = sc->endCTFE();
- exp->upr = exp->upr->implicitCastTo(sc, Type::tsize_t);
- }
- if (sc != scx)
- sc = sc->pop();
- if ((exp->lwr && exp->lwr->type == Type::terror) ||
- (exp->upr && exp->upr->type == Type::terror))
- {
- return setError();
- }
-
- if (t1b->ty == Ttuple)
- {
- exp->lwr = exp->lwr->ctfeInterpret();
- exp->upr = exp->upr->ctfeInterpret();
- uinteger_t i1 = exp->lwr->toUInteger();
- uinteger_t i2 = exp->upr->toUInteger();
-
- TupleExp *te;
- TypeTuple *tup;
- size_t length;
- if (exp->e1->op == TOKtuple) // slicing an expression tuple
- {
- te = (TupleExp *)exp->e1;
- tup = NULL;
- length = te->exps->length;
- }
- else if (exp->e1->op == TOKtype) // slicing a type tuple
- {
- te = NULL;
- tup = (TypeTuple *)t1b;
- length = Parameter::dim(tup->arguments);
- }
- else
- assert(0);
-
- if (i2 < i1 || length < i2)
- {
- exp->error("string slice [%llu .. %llu] is out of bounds", i1, i2);
- return setError();
- }
-
- size_t j1 = (size_t) i1;
- size_t j2 = (size_t) i2;
- Expression *e;
- if (exp->e1->op == TOKtuple)
- {
- Expressions *exps = new Expressions;
- exps->setDim(j2 - j1);
- for (size_t i = 0; i < j2 - j1; i++)
- {
- (*exps)[i] = (*te->exps)[j1 + i];
- }
- e = new TupleExp(exp->loc, te->e0, exps);
- }
- else
- {
- Parameters *args = new Parameters;
- args->reserve(j2 - j1);
- for (size_t i = j1; i < j2; i++)
- {
- Parameter *arg = Parameter::getNth(tup->arguments, i);
- args->push(arg);
- }
- e = new TypeExp(exp->e1->loc, new TypeTuple(args));
- }
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- exp->type = t1b->nextOf()->arrayOf();
- // Allow typedef[] -> typedef[]
- if (exp->type->equals(t1b))
- exp->type = exp->e1->type;
-
- if (exp->lwr && exp->upr)
- {
- exp->lwr = exp->lwr->optimize(WANTvalue);
- exp->upr = exp->upr->optimize(WANTvalue);
-
- IntRange lwrRange = getIntRange(exp->lwr);
- IntRange uprRange = getIntRange(exp->upr);
-
- if (t1b->ty == Tsarray || t1b->ty == Tarray)
- {
- Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
- el = expressionSemantic(el, sc);
- el = el->optimize(WANTvalue);
- if (el->op == TOKint64)
- {
- dinteger_t length = el->toInteger();
- IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length));
- exp->upperIsInBounds = bounds.contains(uprRange);
- }
- }
- else if (t1b->ty == Tpointer)
- {
- exp->upperIsInBounds = true;
- }
- else
- assert(0);
-
- exp->lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
-
- //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", upperIsInBounds, lowerIsLessThanUpper);
- }
-
- result = exp;
- }
-
- void visit(ArrayLengthExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = unaSemantic(e, sc))
- {
- result = ex;
- return;
- }
- e->e1 = resolveProperties(sc, e->e1);
-
- e->type = Type::tsize_t;
- result = e;
- }
-
- void visit(IntervalExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- Expression *le = e->lwr;
- le = expressionSemantic(le, sc);
- le = resolveProperties(sc, le);
-
- Expression *ue = e->upr;
- ue = expressionSemantic(ue, sc);
- ue = resolveProperties(sc, ue);
-
- if (le->op == TOKerror)
- {
- result = le;
- return;
- }
- if (ue->op == TOKerror)
- {
- result = ue;
- return;
- }
-
- e->lwr = le;
- e->upr = ue;
-
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(DelegatePtrExp *e)
- {
- if (!e->type)
- {
- unaSemantic(e, sc);
- e->e1 = resolveProperties(sc, e->e1);
-
- if (e->e1->op == TOKerror)
- {
- result = e->e1;
- return;
- }
- e->type = Type::tvoidptr;
- }
- result = e;
- }
-
- void visit(DelegateFuncptrExp *e)
- {
- if (!e->type)
- {
- unaSemantic(e, sc);
- e->e1 = resolveProperties(sc, e->e1);
-
- if (e->e1->op == TOKerror)
- {
- result = e->e1;
- return;
- }
- e->type = e->e1->type->nextOf()->pointerTo();
- }
- result = e;
- }
-
- void visit(ArrayExp *exp)
- {
- assert(!exp->type);
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (isAggregate(exp->e1->type))
- exp->error("no [] operator overload for type %s", exp->e1->type->toChars());
- else
- exp->error("only one index allowed to index %s", exp->e1->type->toChars());
- return setError();
- }
-
- void visit(DotExp *exp)
- {
- exp->e1 = expressionSemantic(exp->e1, sc);
- exp->e2 = expressionSemantic(exp->e2, sc);
-
- if (exp->e1->op == TOKtype)
- {
- result = exp->e2;
- return;
- }
- if (exp->e2->op == TOKtype)
- {
- result = exp->e2;
- return;
- }
- if (exp->e2->op == TOKtemplate)
- {
- TemplateDeclaration *td = ((TemplateExp *)exp->e2)->td;
- Expression *e = new DotTemplateExp(exp->loc, exp->e1, td);
- result = expressionSemantic(e, sc);
- return;
- }
- if (!exp->type)
- exp->type = exp->e2->type;
- result = exp;
- }
-
- void visit(CommaExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- // Allow `((a,b),(x,y))`
- if (e->allowCommaExp)
- {
- if (e->e1 && e->e1->op == TOKcomma)
- ((CommaExp *)e->e1)->allowCommaExp = true;
- if (e->e2 && e->e2->op == TOKcomma)
- ((CommaExp *)e->e2)->allowCommaExp = true;
- }
-
- if (Expression *ex = binSemanticProp(e, sc))
- {
- result = ex;
- return;
- }
- e->e1 = e->e1->addDtorHook(sc);
-
- if (checkNonAssignmentArrayOp(e->e1))
- return setError();
-
- e->type = e->e2->type;
- if (e->type != Type::tvoid && !e->allowCommaExp && !e->isGenerated)
- e->deprecation("Using the result of a comma expression is deprecated");
- result = e;
- }
-
- void visit(IndexExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- // operator overloading should be handled in ArrayExp already.
-
- if (!exp->e1->type)
- exp->e1 = expressionSemantic(exp->e1, sc);
- assert(exp->e1->type); // semantic() should already be run on it
- if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
- {
- exp->e2 = expressionSemantic(exp->e2, sc);
- exp->e2 = resolveProperties(sc, exp->e2);
- Type *nt;
- if (exp->e2->op == TOKtype)
- nt = new TypeAArray(exp->e1->type, exp->e2->type);
- else
- nt = new TypeSArray(exp->e1->type, exp->e2);
- Expression *e = new TypeExp(exp->loc, nt);
- result = expressionSemantic(e, sc);
- return;
- }
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->e1->type->ty == Terror)
- return setError();
-
- // Note that unlike C we do not implement the int[ptr]
-
- Type *t1b = exp->e1->type->toBasetype();
-
- if (t1b->ty == Tvector)
- {
- // Convert e1 to corresponding static array
- TypeVector *tv1 = (TypeVector *)t1b;
- t1b = tv1->basetype;
- t1b = t1b->castMod(tv1->mod);
- exp->e1->type = t1b;
- }
-
- /* Run semantic on e2
- */
- Scope *scx = sc;
- if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
- {
- // Create scope for 'length' variable
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
- sym->loc = exp->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- }
- if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->e2 = expressionSemantic(exp->e2, sc);
- exp->e2 = resolveProperties(sc, exp->e2);
- if (t1b->ty == Ttuple) sc = sc->endCTFE();
- if (exp->e2->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)exp->e2;
- if (te->exps && te->exps->length == 1)
- exp->e2 = Expression::combine(te->e0, (*te->exps)[0]); // bug 4444 fix
- }
- if (sc != scx)
- sc = sc->pop();
- if (exp->e2->type == Type::terror)
- return setError();
-
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- switch (t1b->ty)
- {
- case Tpointer:
- if (((TypePointer *)t1b)->next->ty == Tfunction)
- {
- exp->error("cannot index function pointer %s", exp->e1->toChars());
- return setError();
- }
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->e2 = exp->e2->optimize(WANTvalue);
- if (exp->e2->op == TOKint64 && exp->e2->toInteger() == 0)
- ;
- else if (sc->func && sc->func->setUnsafe())
- {
- exp->error("safe function `%s` cannot index pointer `%s`",
- sc->func->toPrettyChars(), exp->e1->toChars());
- return setError();
- }
- exp->type = ((TypeNext *)t1b)->next;
- break;
-
- case Tarray:
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->type = ((TypeNext *)t1b)->next;
- break;
-
- case Tsarray:
- {
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->type = t1b->nextOf();
- break;
- }
-
- case Taarray:
- {
- TypeAArray *taa = (TypeAArray *)t1b;
- /* We can skip the implicit conversion if they differ only by
- * constness (Bugzilla 2684, see also bug 2954b)
- */
- if (!arrayTypeCompatibleWithoutCasting(exp->e2->type, taa->index))
- {
- exp->e2 = exp->e2->implicitCastTo(sc, taa->index); // type checking
- if (exp->e2->type == Type::terror)
- return setError();
- }
-
- semanticTypeInfo(sc, taa);
-
- exp->type = taa->next;
- break;
- }
-
- case Ttuple:
- {
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->e2 = exp->e2->ctfeInterpret();
- uinteger_t index = exp->e2->toUInteger();
-
- TupleExp *te;
- TypeTuple *tup;
- size_t length;
- if (exp->e1->op == TOKtuple)
- {
- te = (TupleExp *)exp->e1;
- tup = NULL;
- length = te->exps->length;
- }
- else if (exp->e1->op == TOKtype)
- {
- te = NULL;
- tup = (TypeTuple *)t1b;
- length = Parameter::dim(tup->arguments);
- }
- else
- assert(0);
-
- if (length <= index)
- {
- exp->error("array index [%llu] is outside array bounds [0 .. %llu]",
- index, (ulonglong)length);
- return setError();
- }
-
- Expression *e;
- if (exp->e1->op == TOKtuple)
- {
- e = (*te->exps)[(size_t)index];
- e = Expression::combine(te->e0, e);
- }
- else
- e = new TypeExp(exp->e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type);
- result = e;
- return;
- }
-
- default:
- exp->error("%s must be an array or pointer type, not %s",
- exp->e1->toChars(), exp->e1->type->toChars());
- return setError();
- }
-
- if (t1b->ty == Tsarray || t1b->ty == Tarray)
- {
- Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
- el = expressionSemantic(el, sc);
- el = el->optimize(WANTvalue);
- if (el->op == TOKint64)
- {
- exp->e2 = exp->e2->optimize(WANTvalue);
- dinteger_t length = el->toInteger();
- if (length)
- {
- IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length - 1));
- exp->indexIsInBounds = bounds.contains(getIntRange(exp->e2));
- }
- }
- }
-
- result = exp;
- }
-
- void visit(PostExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e1x = resolveProperties(sc, exp->e1);
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- exp->e1 = e1x;
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->checkReadModifyWrite(exp->op))
- return setError();
- if (exp->e1->op == TOKslice)
- {
- const char *s = exp->op == TOKplusplus ? "increment" : "decrement";
- exp->error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp->e1->toChars(), s);
- return setError();
- }
-
- exp->e1 = exp->e1->optimize(WANTvalue);
-
- Type *t1 = exp->e1->type->toBasetype();
- if (t1->ty == Tclass || t1->ty == Tstruct || exp->e1->op == TOKarraylength)
- {
- /* Check for operator overloading,
- * but rewrite in terms of ++e instead of e++
- */
-
- /* If e1 is not trivial, take a reference to it
- */
- Expression *de = NULL;
- if (exp->e1->op != TOKvar && exp->e1->op != TOKarraylength)
- {
- // ref v = e1;
- VarDeclaration *v = copyToTemp(STCref, "__postref", exp->e1);
- de = new DeclarationExp(exp->loc, v);
- exp->e1 = new VarExp(exp->e1->loc, v);
- }
-
- /* Rewrite as:
- * auto tmp = e1; ++e1; tmp
- */
- VarDeclaration *tmp = copyToTemp(0, "__pitmp", exp->e1);
- Expression *ea = new DeclarationExp(exp->loc, tmp);
-
- Expression *eb = exp->e1->syntaxCopy();
- eb = new PreExp(exp->op == TOKplusplus ? TOKpreplusplus : TOKpreminusminus, exp->loc, eb);
-
- Expression *ec = new VarExp(exp->loc, tmp);
-
- // Combine de,ea,eb,ec
- if (de)
- ea = new CommaExp(exp->loc, de, ea);
- e = new CommaExp(exp->loc, ea, eb);
- e = new CommaExp(exp->loc, e, ec);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
-
- e = exp;
- if (exp->e1->checkScalar())
- return setError();
- if (exp->e1->checkNoBool())
- return setError();
-
- if (exp->e1->type->ty == Tpointer)
- e = scaleFactor(exp, sc);
- else
- exp->e2 = exp->e2->castTo(sc, exp->e1->type);
- e->type = exp->e1->type;
- result = e;
- }
-
- void visit(PreExp *exp)
- {
- Expression *e = exp->op_overload(sc);
- // printf("PreExp::semantic('%s')\n", exp->toChars());
-
- if (e)
- {
- result = e;
- return;
- }
-
- // Rewrite as e1+=1 or e1-=1
- if (exp->op == TOKpreplusplus)
- e = new AddAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
- else
- e = new MinAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
- result = expressionSemantic(e, sc);
- }
-
- void visit(AssignExp *exp)
- {
- //printf("e1->op = %d, '%s'\n", exp->e1->op, Token::toChars(exp->e1->op));
- //printf("e2->op = %d, '%s'\n", exp->e2->op, Token::toChars(exp->e2->op));
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e1old = exp->e1;
-
- if (exp->e2->op == TOKcomma)
- {
- /* Rewrite to get rid of the comma from rvalue
- */
- if (!((CommaExp *)exp->e2)->isGenerated)
- exp->deprecation("Using the result of a comma expression is deprecated");
- Expression *e0;
- exp->e2 = Expression::extractLast(exp->e2, &e0);
- Expression *e = Expression::combine(e0, exp);
- result = expressionSemantic(e, sc);
- return;
- }
-
- /* Look for operator overloading of a[arguments] = e2.
- * Do it before e1->semantic() otherwise the ArrayExp will have been
- * converted to unary operator overloading already.
- */
- if (exp->e1->op == TOKarray)
- {
- Expression *res;
-
- ArrayExp *ae = (ArrayExp *)exp->e1;
- ae->e1 = expressionSemantic(ae->e1, sc);
- ae->e1 = resolveProperties(sc, ae->e1);
- Expression *ae1old = ae->e1;
-
- const bool maybeSlice =
- (ae->arguments->length == 0 ||
- (ae->arguments->length == 1 && (*ae->arguments)[0]->op == TOKinterval));
- IntervalExp *ie = NULL;
- if (maybeSlice && ae->arguments->length)
- {
- assert((*ae->arguments)[0]->op == TOKinterval);
- ie = (IntervalExp *)(*ae->arguments)[0];
- }
-
- while (true)
- {
- if (ae->e1->op == TOKerror)
- {
- result = ae->e1;
- return;
- }
- Expression *e0 = NULL;
- Expression *ae1save = ae->e1;
- ae->lengthVar = NULL;
-
- Type *t1b = ae->e1->type->toBasetype();
- AggregateDeclaration *ad = isAggregate(t1b);
- if (!ad)
- break;
- if (search_function(ad, Id::indexass))
- {
- // Deal with $
- res = resolveOpDollar(sc, ae, &e0);
- if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
- goto Lfallback;
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
-
- res = expressionSemantic(exp->e2, sc);
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
- exp->e2 = res;
-
- /* Rewrite (a[arguments] = e2) as:
- * a.opIndexAssign(e2, arguments)
- */
- Expressions *a = (Expressions *)ae->arguments->copy();
- a->insert(0, exp->e2);
- res = new DotIdExp(exp->loc, ae->e1, Id::indexass);
- res = new CallExp(exp->loc, res, a);
- if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
- res = trySemantic(res, sc);
- else
- res = expressionSemantic(res, sc);
- if (res)
- {
- res = Expression::combine(e0, res);
- result = res;
- return;
- }
- }
- Lfallback:
- if (maybeSlice && search_function(ad, Id::sliceass))
- {
- // Deal with $
- res = resolveOpDollar(sc, ae, ie, &e0);
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
-
- res = expressionSemantic(exp->e2, sc);
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
- exp->e2 = res;
-
- /* Rewrite (a[i..j] = e2) as:
- * a.opSliceAssign(e2, i, j)
- */
- Expressions *a = new Expressions();
- a->push(exp->e2);
- if (ie)
- {
- a->push(ie->lwr);
- a->push(ie->upr);
- }
- res = new DotIdExp(exp->loc, ae->e1, Id::sliceass);
- res = new CallExp(exp->loc, res, a);
- res = expressionSemantic(res, sc);
- res = Expression::combine(e0, res);
- result = res;
- return;
- }
-
- // No operator overloading member function found yet, but
- // there might be an alias this to try.
- if (ad->aliasthis && t1b != ae->att1)
- {
- if (!ae->att1 && t1b->checkAliasThisRec())
- ae->att1 = t1b;
-
- /* Rewrite (a[arguments] op e2) as:
- * a.aliasthis[arguments] op e2
- */
- ae->e1 = resolveAliasThis(sc, ae1save, true);
- if (ae->e1)
- continue;
- }
- break;
- }
- ae->e1 = ae1old; // recovery
- ae->lengthVar = NULL;
- }
-
- /* Run exp->e1 semantic.
- */
- {
- Expression *e1x = exp->e1;
-
- /* With UFCS, e.f = value
- * Could mean:
- * .f(e, value)
- * or:
- * .f(e) = value
- */
- if (e1x->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)e1x;
- Expression *e = semanticY(dti, sc, 1);
- if (!e)
- {
- result = resolveUFCSProperties(sc, e1x, exp->e2);
- return;
- }
- e1x = e;
- }
- else if (e1x->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)e1x;
- Expression *e = semanticY(die, sc, 1);
- if (e && isDotOpDispatch(e))
- {
- unsigned errors = global.startGagging();
- e = resolvePropertiesX(sc, e, exp->e2);
- if (global.endGagging(errors))
- e = NULL; /* fall down to UFCS */
- else
- {
- result = e;
- return;
- }
- }
- if (!e)
- {
- result = resolveUFCSProperties(sc, e1x, exp->e2);
- return;
- }
- e1x = e;
- }
- else
- {
- if (e1x->op == TOKslice)
- ((SliceExp *)e1x)->arrayop = true;
-
- e1x = expressionSemantic(e1x, sc);
- }
-
- /* We have f = value.
- * Could mean:
- * f(value)
- * or:
- * f() = value
- */
- if (Expression *e = resolvePropertiesX(sc, e1x, exp->e2))
- {
- result = e;
- return;
- }
- if (e1x->checkRightThis(sc))
- return setError();
- exp->e1 = e1x;
- assert(exp->e1->type);
- }
- Type *t1 = exp->e1->type->toBasetype();
-
- /* Run exp->e2 semantic.
- * Different from other binary expressions, the analysis of e2
- * depends on the result of e1 in assignments.
- */
- {
- Expression *e2x = inferType(exp->e2, t1->baseElemOf());
-
- e2x = expressionSemantic(e2x, sc);
- e2x = resolveProperties(sc, e2x);
-
- if (e2x->op == TOKtype)
- e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- if (e2x->checkValue())
- return setError();
- exp->e2 = e2x;
- }
-
- /* Rewrite tuple assignment as a tuple of assignments.
- */
- {
- Expression *e2x = exp->e2;
-
- Ltupleassign:
- if (exp->e1->op == TOKtuple && e2x->op == TOKtuple)
- {
- TupleExp *tup1 = (TupleExp *)exp->e1;
- TupleExp *tup2 = (TupleExp *)e2x;
- size_t dim = tup1->exps->length;
- Expression *e = NULL;
- if (dim != tup2->exps->length)
- {
- exp->error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->length);
- return setError();
- }
- if (dim == 0)
- {
- e = new IntegerExp(exp->loc, 0, Type::tint32);
- e = new CastExp(exp->loc, e, Type::tvoid); // avoid "has no effect" error
- e = Expression::combine(Expression::combine(tup1->e0, tup2->e0), e);
- }
- else
- {
- Expressions *exps = new Expressions;
- exps->setDim(dim);
- for (size_t i = 0; i < dim; i++)
- {
- Expression *ex1 = (*tup1->exps)[i];
- Expression *ex2 = (*tup2->exps)[i];
- (*exps)[i] = new AssignExp(exp->loc, ex1, ex2);
- }
- e = new TupleExp(exp->loc, Expression::combine(tup1->e0, tup2->e0), exps);
- }
- result = expressionSemantic(e, sc);
- return;
- }
-
- /* Look for form: e1 = e2->aliasthis.
- */
- if (exp->e1->op == TOKtuple)
- {
- TupleDeclaration *td = isAliasThisTuple(e2x);
- if (!td)
- goto Lnomatch;
-
- assert(exp->e1->type->ty == Ttuple);
- TypeTuple *tt = (TypeTuple *)exp->e1->type;
-
- Expression *e0 = NULL;
- Expression *ev = extractSideEffect(sc, "__tup", &e0, e2x);
-
- Expressions *iexps = new Expressions();
- iexps->push(ev);
-
- for (size_t u = 0; u < iexps->length ; u++)
- {
- Lexpand:
- Expression *e = (*iexps)[u];
-
- Parameter *arg = Parameter::getNth(tt->arguments, u);
- //printf("[%d] iexps->length = %d, ", u, iexps->length);
- //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
- //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
-
- if (!arg || !e->type->implicitConvTo(arg->type))
- {
- // expand initializer to tuple
- if (expandAliasThisTuples(iexps, u) != -1)
- {
- if (iexps->length <= u)
- break;
- goto Lexpand;
- }
- goto Lnomatch;
- }
- }
- e2x = new TupleExp(e2x->loc, e0, iexps);
- e2x = expressionSemantic(e2x, sc);
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- // Do not need to overwrite exp->e2
- goto Ltupleassign;
- }
- Lnomatch:
- ;
- }
-
- /* Inside constructor, if this is the first assignment of object field,
- * rewrite this to initializing the field.
- */
- if (exp->op == TOKassign && exp->e1->checkModifiable(sc) == 2)
- {
- //printf("[%s] change to init - %s\n", exp->loc.toChars(), toChars());
- exp->op = TOKconstruct;
-
- // Bugzilla 13515: set Index::modifiable flag for complex AA element initialization
- if (exp->e1->op == TOKindex)
- {
- Expression *e1x = ((IndexExp *)exp->e1)->markSettingAAElem();
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- }
- }
- else if (exp->op == TOKconstruct && exp->e1->op == TOKvar &&
- ((VarExp *)exp->e1)->var->storage_class & (STCout | STCref))
- {
- exp->memset |= referenceInit;
- }
-
- /* If it is an assignment from a 'foreign' type,
- * check for operator overloading.
- */
- if (exp->memset & referenceInit)
- {
- // If this is an initialization of a reference,
- // do nothing
- }
- else if (t1->ty == Tstruct)
- {
- Expression *e1x = exp->e1;
- Expression *e2x = exp->e2;
- StructDeclaration *sd = ((TypeStruct *)t1)->sym;
-
- if (exp->op == TOKconstruct)
- {
- Type *t2 = e2x->type->toBasetype();
- if (t2->ty == Tstruct && sd == ((TypeStruct *)t2)->sym)
- {
- sd->size(exp->loc);
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
-
- // Bugzilla 15661: Look for the form from last of comma chain.
- Expression *e2y = e2x;
- while (e2y->op == TOKcomma)
- e2y = ((CommaExp *)e2y)->e2;
-
- CallExp *ce = (e2y->op == TOKcall) ? (CallExp *)e2y : NULL;
- DotVarExp *dve = (ce && ce->e1->op == TOKdotvar)
- ? (DotVarExp *)ce->e1 : NULL;
- if (sd->ctor && ce && dve && dve->var->isCtorDeclaration() &&
- e2y->type->implicitConvTo(t1))
- {
- /* Look for form of constructor call which is:
- * __ctmp.ctor(arguments...)
- */
-
- /* Before calling the constructor, initialize
- * variable with a bit copy of the default
- * initializer
- */
- AssignExp *ae = exp;
- if (sd->zeroInit == 1 && !sd->isNested())
- {
- // Bugzilla 14606: Always use BlitExp for the special expression: (struct = 0)
- ae = new BlitExp(ae->loc, ae->e1, new IntegerExp(exp->loc, 0, Type::tint32));
- }
- else
- {
- // Keep ae->op == TOKconstruct
- ae->e2 = sd->isNested() ? t1->defaultInitLiteral(exp->loc) : t1->defaultInit(exp->loc);
- }
- ae->type = e1x->type;
-
- /* Replace __ctmp being constructed with e1.
- * We need to copy constructor call expression,
- * because it may be used in other place.
- */
- DotVarExp *dvx = (DotVarExp *)dve->copy();
- dvx->e1 = e1x;
- CallExp *cx = (CallExp *)ce->copy();
- cx->e1 = dvx;
-
- Expression *e0;
- Expression::extractLast(e2x, &e0);
-
- Expression *e = Expression::combine(ae, cx);
- e = Expression::combine(e0, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (sd->postblit)
- {
- /* We have a copy constructor for this
- */
- if (e2x->op == TOKquestion)
- {
- /* Rewrite as:
- * a ? e1 = b : e1 = c;
- */
- CondExp *econd = (CondExp *)e2x;
- Expression *ea1 = new ConstructExp(econd->e1->loc, e1x, econd->e1);
- Expression *ea2 = new ConstructExp(econd->e1->loc, e1x, econd->e2);
- Expression *e = new CondExp(exp->loc, econd->econd, ea1, ea2);
- result = expressionSemantic(e, sc);
- return;
- }
-
- if (e2x->isLvalue())
- {
- if (!e2x->type->implicitConvTo(e1x->type))
- {
- exp->error("conversion error from %s to %s", e2x->type->toChars(), e1x->type->toChars());
- return setError();
- }
-
- /* Rewrite as:
- * (e1 = e2).postblit();
- *
- * Blit assignment e1 = e2 returns a reference to the original e1,
- * then call the postblit on it.
- */
- Expression *e = e1x->copy();
- e->type = e->type->mutableOf();
- e = new BlitExp(exp->loc, e, e2x);
- e = new DotVarExp(exp->loc, e, sd->postblit, false);
- e = new CallExp(exp->loc, e);
- result = expressionSemantic(e, sc);
- return;
- }
- else
- {
- /* The struct value returned from the function is transferred
- * so should not call the destructor on it.
- */
- e2x = valueNoDtor(e2x);
- }
- }
- }
- else if (!e2x->implicitConvTo(t1))
- {
- sd->size(exp->loc);
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
-
- if (sd->ctor)
- {
- /* Look for implicit constructor call
- * Rewrite as:
- * e1 = init, e1.ctor(e2)
- */
- Expression *einit;
- einit = new BlitExp(exp->loc, e1x, e1x->type->defaultInit(exp->loc));
- einit->type = e1x->type;
-
- Expression *e;
- e = new DotIdExp(exp->loc, e1x, Id::ctor);
- e = new CallExp(exp->loc, e, e2x);
- e = new CommaExp(exp->loc, einit, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (search_function(sd, Id::call))
- {
- /* Look for static opCall
- * (See bugzilla 2702 for more discussion)
- * Rewrite as:
- * e1 = typeof(e1).opCall(arguments)
- */
- e2x = typeDotIdExp(e2x->loc, e1x->type, Id::call);
- e2x = new CallExp(exp->loc, e2x, exp->e2);
-
- e2x = expressionSemantic(e2x, sc);
- e2x = resolveProperties(sc, e2x);
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- if (e2x->checkValue())
- return setError();
- }
- }
- else // Bugzilla 11355
- {
- AggregateDeclaration *ad2 = isAggregate(e2x->type);
- if (ad2 && ad2->aliasthis && !(exp->att2 && e2x->type == exp->att2))
- {
- if (!exp->att2 && exp->e2->type->checkAliasThisRec())
- exp->att2 = exp->e2->type;
-
- /* Rewrite (e1 op e2) as:
- * (e1 op e2.aliasthis)
- */
- exp->e2 = new DotIdExp(exp->e2->loc, exp->e2, ad2->aliasthis->ident);
- result = expressionSemantic(exp, sc);
- return;
- }
- }
- }
- else if (exp->op == TOKassign)
- {
- if (e1x->op == TOKindex &&
- ((IndexExp *)e1x)->e1->type->toBasetype()->ty == Taarray)
- {
- /*
- * Rewrite:
- * aa[key] = e2;
- * as:
- * ref __aatmp = aa;
- * ref __aakey = key;
- * ref __aaval = e2;
- * (__aakey in __aatmp
- * ? __aatmp[__aakey].opAssign(__aaval)
- * : ConstructExp(__aatmp[__aakey], __aaval));
- */
- IndexExp *ie = (IndexExp *)e1x;
- Type *t2 = e2x->type->toBasetype();
-
- Expression *e0 = NULL;
- Expression *ea = extractSideEffect(sc, "__aatmp", &e0, ie->e1);
- Expression *ek = extractSideEffect(sc, "__aakey", &e0, ie->e2);
- Expression *ev = extractSideEffect(sc, "__aaval", &e0, e2x);
-
- AssignExp *ae = (AssignExp *)exp->copy();
- ae->e1 = new IndexExp(exp->loc, ea, ek);
- ae->e1 = expressionSemantic(ae->e1, sc);
- ae->e1 = ae->e1->optimize(WANTvalue);
- ae->e2 = ev;
- Expression *e = ae->op_overload(sc);
- if (e)
- {
- Expression *ey = NULL;
- if (t2->ty == Tstruct && sd == t2->toDsymbol(sc))
- {
- ey = ev;
- }
- else if (!ev->implicitConvTo(ie->type) && sd->ctor)
- {
- // Look for implicit constructor call
- // Rewrite as S().ctor(e2)
- ey = new StructLiteralExp(exp->loc, sd, NULL);
- ey = new DotIdExp(exp->loc, ey, Id::ctor);
- ey = new CallExp(exp->loc, ey, ev);
- ey = trySemantic(ey, sc);
- }
- if (ey)
- {
- Expression *ex;
- ex = new IndexExp(exp->loc, ea, ek);
- ex = expressionSemantic(ex, sc);
- ex = ex->optimize(WANTvalue);
- ex = ex->modifiableLvalue(sc, ex); // allocate new slot
- ey = new ConstructExp(exp->loc, ex, ey);
- ey = expressionSemantic(ey, sc);
- if (ey->op == TOKerror)
- {
- result = ey;
- return;
- }
- ex = e;
-
- // Bugzilla 14144: The whole expression should have the common type
- // of opAssign() return and assigned AA entry.
- // Even if there's no common type, expression should be typed as void.
- Type *t = NULL;
- if (!typeMerge(sc, TOKquestion, &t, &ex, &ey))
- {
- ex = new CastExp(ex->loc, ex, Type::tvoid);
- ey = new CastExp(ey->loc, ey, Type::tvoid);
- }
- e = new CondExp(exp->loc, new InExp(exp->loc, ek, ea), ex, ey);
- }
- e = Expression::combine(e0, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- else
- {
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- }
- else
- assert(exp->op == TOKblit);
-
- exp->e1 = e1x;
- exp->e2 = e2x;
- }
- else if (t1->ty == Tclass)
- {
- // Disallow assignment operator overloads for same type
- if (exp->op == TOKassign && !exp->e2->implicitConvTo(exp->e1->type))
- {
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- }
- else if (t1->ty == Tsarray)
- {
- // SliceExp cannot have static array type without context inference.
- assert(exp->e1->op != TOKslice);
-
- Expression *e1x = exp->e1;
- Expression *e2x = exp->e2;
-
- if (e2x->implicitConvTo(e1x->type))
- {
- if (exp->op != TOKblit &&
- ((e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op == TOKcast && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op != TOKslice && e2x->isLvalue())))
- {
- if (e1x->checkPostblit(sc, t1))
- return setError();
- }
-
- // e2 matches to t1 because of the implicit length match, so
- if (isUnaArrayOp(e2x->op) || isBinArrayOp(e2x->op))
- {
- // convert e1 to e1[]
- // e.g. e1[] = a[] + b[];
- SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
- sle->arrayop = true;
- e1x = expressionSemantic(sle, sc);
- }
- else
- {
- // convert e2 to t1 later
- // e.g. e1 = [1, 2, 3];
- }
- }
- else
- {
- if (e2x->implicitConvTo(t1->nextOf()->arrayOf()) > MATCHnomatch)
- {
- uinteger_t dim1 = ((TypeSArray *)t1)->dim->toInteger();
- uinteger_t dim2 = dim1;
- if (e2x->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e2x;
- dim2 = ale->elements ? ale->elements->length : 0;
- }
- else if (e2x->op == TOKslice)
- {
- Type *tx = toStaticArrayType((SliceExp *)e2x);
- if (tx)
- dim2 = ((TypeSArray *)tx)->dim->toInteger();
- }
- if (dim1 != dim2)
- {
- exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
- return setError();
- }
- }
-
- // May be block or element-wise assignment, so
- // convert e1 to e1[]
- if (exp->op != TOKassign)
- {
- // If multidimensional static array, treat as one large array
- dinteger_t dim = t1->numberOfElems(exp->loc);
- e1x->type = t1->baseElemOf()->sarrayOf(dim);
- }
- SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
- sle->arrayop = true;
- e1x = expressionSemantic(sle, sc);
- }
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
-
- exp->e1 = e1x;
- exp->e2 = e2x;
- t1 = e1x->type->toBasetype();
- }
-
- /* Check the mutability of e1.
- */
- if (exp->e1->op == TOKarraylength)
- {
- // e1 is not an lvalue, but we let code generator handle it
- ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
-
- Expression *ale1x = ale->e1;
- ale1x = ale1x->modifiableLvalue(sc, exp->e1);
- if (ale1x->op == TOKerror)
- {
- result = ale1x;
- return;
- }
- ale->e1 = ale1x;
-
- Type *tn = ale->e1->type->toBasetype()->nextOf();
- checkDefCtor(ale->loc, tn);
- semanticTypeInfo(sc, tn);
- }
- else if (exp->e1->op == TOKslice)
- {
- Type *tn = exp->e1->type->nextOf();
- if (exp->op == TOKassign && !tn->isMutable())
- {
- exp->error("slice %s is not mutable", exp->e1->toChars());
- return setError();
- }
-
- // For conditional operator, both branches need conversion.
- SliceExp *se = (SliceExp *)exp->e1;
- while (se->e1->op == TOKslice)
- se = (SliceExp *)se->e1;
- if (se->e1->op == TOKquestion &&
- se->e1->type->toBasetype()->ty == Tsarray)
- {
- se->e1 = se->e1->modifiableLvalue(sc, exp->e1);
- if (se->e1->op == TOKerror)
- {
- result = se->e1;
- return;
- }
- }
- }
- else
- {
- Expression *e1x = exp->e1;
-
- // Try to do a decent error message with the expression
- // before it got constant folded
- if (e1x->op != TOKvar)
- e1x = e1x->optimize(WANTvalue);
-
- if (exp->op == TOKassign)
- e1x = e1x->modifiableLvalue(sc, e1old);
-
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- exp->e1 = e1x;
- }
-
- /* Tweak e2 based on the type of e1.
- */
- Expression *e2x = exp->e2;
- Type *t2 = e2x->type->toBasetype();
-
- // If it is a array, get the element type. Note that it may be
- // multi-dimensional.
- Type *telem = t1;
- while (telem->ty == Tarray)
- telem = telem->nextOf();
-
- if (exp->e1->op == TOKslice &&
- t1->nextOf() && (telem->ty != Tvoid || e2x->op == TOKnull) &&
- e2x->implicitConvTo(t1->nextOf())
- )
- {
- // Check for block assignment. If it is of type void[], void[][], etc,
- // '= null' is the only allowable block assignment (Bug 7493)
- // memset
- exp->memset |= blockAssign; // make it easy for back end to tell what this is
- e2x = e2x->implicitCastTo(sc, t1->nextOf());
- if (exp->op != TOKblit && e2x->isLvalue() &&
- exp->e1->checkPostblit(sc, t1->nextOf()))
- return setError();
- }
- else if (exp->e1->op == TOKslice &&
- (t2->ty == Tarray || t2->ty == Tsarray) &&
- t2->nextOf()->implicitConvTo(t1->nextOf()))
- {
- // Check element-wise assignment.
-
- /* If assigned elements number is known at compile time,
- * check the mismatch.
- */
- SliceExp *se1 = (SliceExp *)exp->e1;
- TypeSArray *tsa1 = (TypeSArray *)toStaticArrayType(se1);
- TypeSArray *tsa2 = NULL;
- if (e2x->op == TOKarrayliteral)
- tsa2 = (TypeSArray *)t2->nextOf()->sarrayOf(((ArrayLiteralExp *)e2x)->elements->length);
- else if (e2x->op == TOKslice)
- tsa2 = (TypeSArray *)toStaticArrayType((SliceExp *)e2x);
- else if (t2->ty == Tsarray)
- tsa2 = (TypeSArray *)t2;
- if (tsa1 && tsa2)
- {
- uinteger_t dim1 = tsa1->dim->toInteger();
- uinteger_t dim2 = tsa2->dim->toInteger();
- if (dim1 != dim2)
- {
- exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
- return setError();
- }
- }
-
- if (exp->op != TOKblit &&
- ((e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op == TOKcast && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op != TOKslice && e2x->isLvalue())))
- {
- if (exp->e1->checkPostblit(sc, t1->nextOf()))
- return setError();
- }
-
- if (0 && global.params.warnings != DIAGNOSTICoff && !global.gag && exp->op == TOKassign &&
- e2x->op != TOKslice && e2x->op != TOKassign &&
- e2x->op != TOKarrayliteral && e2x->op != TOKstring &&
- !(e2x->op == TOKadd || e2x->op == TOKmin ||
- e2x->op == TOKmul || e2x->op == TOKdiv ||
- e2x->op == TOKmod || e2x->op == TOKxor ||
- e2x->op == TOKand || e2x->op == TOKor ||
- e2x->op == TOKpow ||
- e2x->op == TOKtilde || e2x->op == TOKneg))
- {
- const char* e1str = exp->e1->toChars();
- const char* e2str = e2x->toChars();
- exp->warning("explicit element-wise assignment %s = (%s)[] is better than %s = %s",
- e1str, e2str, e1str, e2str);
- }
-
- Type *t2n = t2->nextOf();
- Type *t1n = t1->nextOf();
- int offset;
- if (t2n->equivalent(t1n) ||
- (t1n->isBaseOf(t2n, &offset) && offset == 0))
- {
- /* Allow copy of distinct qualifier elements.
- * eg.
- * char[] dst; const(char)[] src;
- * dst[] = src;
- *
- * class C {} class D : C {}
- * C[2] ca; D[] da;
- * ca[] = da;
- */
- if (isArrayOpValid(e2x))
- {
- // Don't add CastExp to keep AST for array operations
- e2x = e2x->copy();
- e2x->type = exp->e1->type->constOf();
- }
- else
- e2x = e2x->castTo(sc, exp->e1->type->constOf());
- }
- else
- {
- /* Bugzilla 15778: A string literal has an array type of immutable
- * elements by default, and normally it cannot be convertible to
- * array type of mutable elements. But for element-wise assignment,
- * elements need to be const at best. So we should give a chance
- * to change code unit size for polysemous string literal.
- */
- if (e2x->op == TOKstring)
- e2x = e2x->implicitCastTo(sc, exp->e1->type->constOf());
- else
- e2x = e2x->implicitCastTo(sc, exp->e1->type);
- }
- if (t1n->toBasetype()->ty == Tvoid && t2n->toBasetype()->ty == Tvoid)
- {
- if (!sc->intypeof && sc->func && sc->func->setUnsafe())
- {
- exp->error("cannot copy void[] to void[] in @safe code");
- return setError();
- }
- }
- }
- else
- {
- if (0 && global.params.warnings != DIAGNOSTICoff && !global.gag && exp->op == TOKassign &&
- t1->ty == Tarray && t2->ty == Tsarray &&
- e2x->op != TOKslice &&
- t2->implicitConvTo(t1))
- { // Disallow ar[] = sa (Converted to ar[] = sa[])
- // Disallow da = sa (Converted to da = sa[])
- const char* e1str = exp->e1->toChars();
- const char* e2str = e2x->toChars();
- const char* atypestr = exp->e1->op == TOKslice ? "element-wise" : "slice";
- exp->warning("explicit %s assignment %s = (%s)[] is better than %s = %s",
- atypestr, e1str, e2str, e1str, e2str);
- }
- if (exp->op == TOKblit)
- e2x = e2x->castTo(sc, exp->e1->type);
- else
- e2x = e2x->implicitCastTo(sc, exp->e1->type);
- }
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- exp->e2 = e2x;
- t2 = exp->e2->type->toBasetype();
-
- /* Look for array operations
- */
- if ((t2->ty == Tarray || t2->ty == Tsarray) && isArrayOpValid(exp->e2))
- {
- // Look for valid array operations
- if (!(exp->memset & blockAssign) && exp->e1->op == TOKslice &&
- (isUnaArrayOp(exp->e2->op) || isBinArrayOp(exp->e2->op)))
- {
- exp->type = exp->e1->type;
- if (exp->op == TOKconstruct) // Bugzilla 10282: tweak mutability of e1 element
- exp->e1->type = exp->e1->type->nextOf()->mutableOf()->arrayOf();
- result = arrayOp(exp, sc);
- return;
- }
-
- // Drop invalid array operations in e2
- // d = a[] + b[], d = (a[] + b[])[0..2], etc
- if (checkNonAssignmentArrayOp(exp->e2, !(exp->memset & blockAssign) && exp->op == TOKassign))
- return setError();
-
- // Remains valid array assignments
- // d = d[], d = [1,2,3], etc
- }
-
- /* Don't allow assignment to classes that were allocated on the stack with:
- * scope Class c = new Class();
- */
-
- if (exp->e1->op == TOKvar && exp->op == TOKassign)
- {
- VarExp *ve = (VarExp *)exp->e1;
- VarDeclaration *vd = ve->var->isVarDeclaration();
- if (vd && (vd->onstack || vd->mynew))
- {
- assert(t1->ty == Tclass);
- exp->error("cannot rebind scope variables");
- }
- }
- if (exp->e1->op == TOKvar && ((VarExp *)exp->e1)->var->ident == Id::ctfe)
- {
- exp->error("cannot modify compiler-generated variable __ctfe");
- }
-
- exp->type = exp->e1->type;
- assert(exp->type);
- Expression *res = exp->op == TOKassign ? exp->reorderSettingAAElem(sc) : exp;
- checkAssignEscape(sc, res, false);
- result = res;
- }
-
- void visit(CatAssignExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- //printf("CatAssignExp::semantic() %s\n", toChars());
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)exp->e1;
- if (se->e1->type->toBasetype()->ty == Tsarray)
- {
- exp->error("cannot append to static array %s", se->e1->type->toChars());
- return setError();
- }
- }
-
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->e2->op == TOKerror)
- {
- result = exp->e2;
- return;
- }
-
- if (checkNonAssignmentArrayOp(exp->e2))
- return setError();
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb1next = tb1->nextOf();
- Type *tb2 = exp->e2->type->toBasetype();
-
- if ((tb1->ty == Tarray) &&
- (tb2->ty == Tarray || tb2->ty == Tsarray) &&
- (exp->e2->implicitConvTo(exp->e1->type)
- || (tb2->nextOf()->implicitConvTo(tb1next) &&
- (tb2->nextOf()->size(Loc()) == tb1next->size(Loc())))
- )
- )
- {
- // Append array
- if (exp->e1->checkPostblit(sc, tb1next))
- return setError();
- exp->e2 = exp->e2->castTo(sc, exp->e1->type);
- }
- else if ((tb1->ty == Tarray) &&
- exp->e2->implicitConvTo(tb1next)
- )
- {
- // Append element
- if (exp->e2->checkPostblit(sc, tb2))
- return setError();
- exp->e2 = exp->e2->castTo(sc, tb1next);
- exp->e2 = doCopyOrMove(sc, exp->e2);
- }
- else if (tb1->ty == Tarray &&
- (tb1next->ty == Tchar || tb1next->ty == Twchar) &&
- exp->e2->type->ty != tb1next->ty &&
- exp->e2->implicitConvTo(Type::tdchar)
- )
- { // Append dchar to char[] or wchar[]
- exp->e2 = exp->e2->castTo(sc, Type::tdchar);
-
- /* Do not allow appending wchar to char[] because if wchar happens
- * to be a surrogate pair, nothing good can result.
- */
- }
- else
- {
- exp->error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars());
- return setError();
- }
- if (exp->e2->checkValue())
- return setError();
-
- exp->type = exp->e1->type;
- result = exp->reorderSettingAAElem(sc);
- }
-
- void visit(PowAssignExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
- return setError();
-
- assert(exp->e1->type && exp->e2->type);
- if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
- {
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- // T[] ^^= ...
- if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
- {
- // T[] ^^= T
- exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
- }
- else if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- // Check element types are arithmetic
- Type *tb1 = exp->e1->type->nextOf()->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
- if (tb2->ty == Tarray || tb2->ty == Tsarray)
- tb2 = tb2->nextOf()->toBasetype();
-
- if ( (tb1->isintegral() || tb1->isfloating()) &&
- (tb2->isintegral() || tb2->isfloating()))
- {
- exp->type = exp->e1->type;
- result = arrayOp(exp, sc);
- return;
- }
- }
- else
- {
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
- }
-
- if ((exp->e1->type->isintegral() || exp->e1->type->isfloating()) &&
- (exp->e2->type->isintegral() || exp->e2->type->isfloating()))
- {
- Expression *e0 = NULL;
- e = exp->reorderSettingAAElem(sc);
- e = Expression::extractLast(e, &e0);
- assert(e == exp);
-
- if (exp->e1->op == TOKvar)
- {
- // Rewrite: e1 = e1 ^^ e2
- e = new PowExp(exp->loc, exp->e1->syntaxCopy(), exp->e2);
- e = new AssignExp(exp->loc, exp->e1, e);
- }
- else
- {
- // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
- VarDeclaration *v = copyToTemp(STCref, "__powtmp", exp->e1);
- Expression *de = new DeclarationExp(exp->e1->loc, v);
- VarExp *ve = new VarExp(exp->e1->loc, v);
- e = new PowExp(exp->loc, ve, exp->e2);
- e = new AssignExp(exp->loc, new VarExp(exp->e1->loc, v), e);
- e = new CommaExp(exp->loc, de, e);
- }
- e = Expression::combine(e0, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- result = exp->incompatibleTypes();
- }
-
- void visit(AddExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
-
- bool err = false;
- if (tb1->ty == Tdelegate ||
- (tb1->ty == Tpointer && tb1->nextOf()->ty == Tfunction))
- {
- err |= exp->e1->checkArithmetic();
- }
- if (tb2->ty == Tdelegate ||
- (tb2->ty == Tpointer && tb2->nextOf()->ty == Tfunction))
- {
- err |= exp->e2->checkArithmetic();
- }
- if (err)
- return setError();
-
- if ((tb1->ty == Tpointer && exp->e2->type->isintegral()) ||
- (tb2->ty == Tpointer && exp->e1->type->isintegral()))
- {
- result = scaleFactor(exp, sc);
- return;
- }
-
- if (tb1->ty == Tpointer && tb2->ty == Tpointer)
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- tb1 = exp->e1->type->toBasetype();
- if (!target.isVectorOpSupported(tb1, exp->op, tb2))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if ((tb1->isreal() && exp->e2->type->isimaginary()) ||
- (tb1->isimaginary() && exp->e2->type->isreal()))
- {
- switch (exp->type->toBasetype()->ty)
- {
- case Tfloat32:
- case Timaginary32:
- exp->type = Type::tcomplex32;
- break;
-
- case Tfloat64:
- case Timaginary64:
- exp->type = Type::tcomplex64;
- break;
-
- case Tfloat80:
- case Timaginary80:
- exp->type = Type::tcomplex80;
- break;
-
- default:
- assert(0);
- }
- }
- result = exp;
- }
-
- void visit(MinExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
-
- bool err = false;
- if (t1->ty == Tdelegate ||
- (t1->ty == Tpointer && t1->nextOf()->ty == Tfunction))
- {
- err |= exp->e1->checkArithmetic();
- }
- if (t2->ty == Tdelegate ||
- (t2->ty == Tpointer && t2->nextOf()->ty == Tfunction))
- {
- err |= exp->e2->checkArithmetic();
- }
- if (err)
- return setError();
-
- if (t1->ty == Tpointer)
- {
- if (t2->ty == Tpointer)
- {
- // Need to divide the result by the stride
- // Replace (ptr - ptr) with (ptr - ptr) / stride
- d_int64 stride;
-
- // make sure pointer types are compatible
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- exp->type = Type::tptrdiff_t;
- stride = t2->nextOf()->size();
- if (stride == 0)
- {
- e = new IntegerExp(exp->loc, 0, Type::tptrdiff_t);
- }
- else
- {
- e = new DivExp(exp->loc, exp, new IntegerExp(Loc(), stride, Type::tptrdiff_t));
- e->type = Type::tptrdiff_t;
- }
- }
- else if (t2->isintegral())
- e = scaleFactor(exp, sc);
- else
- {
- exp->error("can't subtract %s from pointer", t2->toChars());
- e = new ErrorExp();
- }
- result = e;
- return;
- }
- if (t2->ty == Tpointer)
- {
- exp->type = exp->e2->type;
- exp->error("can't subtract pointer from %s", exp->e1->type->toChars());
- return setError();
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- t1 = exp->e1->type->toBasetype();
- t2 = exp->e2->type->toBasetype();
- if (!target.isVectorOpSupported(t1, exp->op, t2))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if ((t1->isreal() && t2->isimaginary()) ||
- (t1->isimaginary() && t2->isreal()))
- {
- switch (exp->type->ty)
- {
- case Tfloat32:
- case Timaginary32:
- exp->type = Type::tcomplex32;
- break;
-
- case Tfloat64:
- case Timaginary64:
- exp->type = Type::tcomplex64;
- break;
-
- case Tfloat80:
- case Timaginary80:
- exp->type = Type::tcomplex80;
- break;
-
- default:
- assert(0);
- }
- }
- result = exp;
- }
-
- void visit(CatExp *exp)
- {
- //printf("CatExp::semantic() %s\n", exp->toChars());
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- /* BUG: Should handle things like:
- * char c;
- * c ~ ' '
- * ' ' ~ c;
- */
- Type *tb1next = tb1->nextOf();
- Type *tb2next = tb2->nextOf();
-
- // Check for: array ~ array
- if (tb1next && tb2next &&
- (tb1next->implicitConvTo(tb2next) >= MATCHconst ||
- tb2next->implicitConvTo(tb1next) >= MATCHconst ||
- (exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2)) ||
- (exp->e2->op == TOKarrayliteral && exp->e2->implicitConvTo(tb1))
- )
- )
- {
- /* Bugzilla 9248: Here to avoid the case of:
- * void*[] a = [cast(void*)1];
- * void*[] b = [cast(void*)2];
- * a ~ b;
- * becoming:
- * a ~ [cast(void*)b];
- */
-
- /* Bugzilla 14682: Also to avoid the case of:
- * int[][] a;
- * a ~ [];
- * becoming:
- * a ~ cast(int[])[];
- */
- goto Lpeer;
- }
-
- // Check for: array ~ element
- if ((tb1->ty == Tsarray || tb1->ty == Tarray) && tb2->ty != Tvoid)
- {
- if (exp->e1->op == TOKarrayliteral)
- {
- exp->e2 = exp->e2->isLvalue() ? callCpCtor(sc, exp->e2) : valueNoDtor(exp->e2);
- // Bugzilla 14686: Postblit call appears in AST, and this is
- // finally translated to an ArrayLiteralExp in below otpimize().
- }
- else if (exp->e1->op == TOKstring)
- {
- // No postblit call exists on character (integer) value.
- }
- else
- {
- if (exp->e2->checkPostblit(sc, tb2))
- return setError();
- // Postblit call will be done in runtime helper function
- }
-
- if (exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2->arrayOf()))
- {
- exp->e1 = exp->e1->implicitCastTo(sc, tb2->arrayOf());
- exp->type = tb2->arrayOf();
- goto L2elem;
- }
- if (exp->e2->implicitConvTo(tb1next) >= MATCHconvert)
- {
- exp->e2 = exp->e2->implicitCastTo(sc, tb1next);
- exp->type = tb1next->arrayOf();
- L2elem:
- if (tb2->ty == Tarray || tb2->ty == Tsarray)
- {
- // Make e2 into [e2]
- exp->e2 = new ArrayLiteralExp(exp->e2->loc, exp->type, exp->e2);
- }
- result = exp->optimize(WANTvalue);
- return;
- }
- }
- // Check for: element ~ array
- if ((tb2->ty == Tsarray || tb2->ty == Tarray) && tb1->ty != Tvoid)
- {
- if (exp->e2->op == TOKarrayliteral)
- {
- exp->e1 = exp->e1->isLvalue() ? callCpCtor(sc, exp->e1) : valueNoDtor(exp->e1);
- }
- else if (exp->e2->op == TOKstring)
- {
- }
- else
- {
- if (exp->e1->checkPostblit(sc, tb1))
- return setError();
- }
-
- if (exp->e2->op == TOKarrayliteral && exp->e2->implicitConvTo(tb1->arrayOf()))
- {
- exp->e2 = exp->e2->implicitCastTo(sc, tb1->arrayOf());
- exp->type = tb1->arrayOf();
- goto L1elem;
- }
- if (exp->e1->implicitConvTo(tb2next) >= MATCHconvert)
- {
- exp->e1 = exp->e1->implicitCastTo(sc, tb2next);
- exp->type = tb2next->arrayOf();
- L1elem:
- if (tb1->ty == Tarray || tb1->ty == Tsarray)
- {
- // Make e1 into [e1]
- exp->e1 = new ArrayLiteralExp(exp->e1->loc, exp->type, exp->e1);
- }
- result = exp->optimize(WANTvalue);
- return;
- }
- }
-
- Lpeer:
- if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
- (tb2->ty == Tsarray || tb2->ty == Tarray) &&
- (tb1next->mod || tb2next->mod) &&
- (tb1next->mod != tb2next->mod)
- )
- {
- Type *t1 = tb1next->mutableOf()->constOf()->arrayOf();
- Type *t2 = tb2next->mutableOf()->constOf()->arrayOf();
- if (exp->e1->op == TOKstring && !((StringExp *)exp->e1)->committed)
- exp->e1->type = t1;
- else
- exp->e1 = exp->e1->castTo(sc, t1);
- if (exp->e2->op == TOKstring && !((StringExp *)exp->e2)->committed)
- exp->e2->type = t2;
- else
- exp->e2 = exp->e2->castTo(sc, t2);
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- exp->type = exp->type->toHeadMutable();
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tsarray)
- exp->type = tb->nextOf()->arrayOf();
- if (exp->type->ty == Tarray && tb1next && tb2next &&
- tb1next->mod != tb2next->mod)
- {
- exp->type = exp->type->nextOf()->toHeadMutable()->arrayOf();
- }
- if (Type *tbn = tb->nextOf())
- {
- if (exp->checkPostblit(sc, tbn))
- return setError();
- }
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
- if ((t1->ty == Tarray || t1->ty == Tsarray) &&
- (t2->ty == Tarray || t2->ty == Tsarray))
- {
- // Normalize to ArrayLiteralExp or StringExp as far as possible
- e = exp->optimize(WANTvalue);
- }
- else
- {
- //printf("(%s) ~ (%s)\n", exp->e1->toChars(), exp->e2->toChars());
- result = exp->incompatibleTypes();
- return;
- }
- result = e;
- }
-
- void visit(MulExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (exp->type->isfloating())
- {
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
-
- if (t1->isreal())
- {
- exp->type = t2;
- }
- else if (t2->isreal())
- {
- exp->type = t1;
- }
- else if (t1->isimaginary())
- {
- if (t2->isimaginary())
- {
-
- switch (t1->toBasetype()->ty)
- {
- case Timaginary32:
- exp->type = Type::tfloat32;
- break;
-
- case Timaginary64:
- exp->type = Type::tfloat64;
- break;
-
- case Timaginary80:
- exp->type = Type::tfloat80;
- break;
-
- default:
- assert(0);
- }
-
- // iy * iv = -yv
- exp->e1->type = exp->type;
- exp->e2->type = exp->type;
- e = new NegExp(exp->loc, exp);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- else
- exp->type = t2; // t2 is complex
- }
- else if (t2->isimaginary())
- {
- exp->type = t1; // t1 is complex
- }
- }
- else if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- result = exp;
- }
-
- void visit(DivExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (exp->type->isfloating())
- {
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
-
- if (t1->isreal())
- {
- exp->type = t2;
- if (t2->isimaginary())
- {
- // x/iv = i(-x/v)
- exp->e2->type = t1;
- e = new NegExp(exp->loc, exp);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- else if (t2->isreal())
- {
- exp->type = t1;
- }
- else if (t1->isimaginary())
- {
- if (t2->isimaginary())
- {
- switch (t1->toBasetype()->ty)
- {
- case Timaginary32:
- exp->type = Type::tfloat32;
- break;
-
- case Timaginary64:
- exp->type = Type::tfloat64;
- break;
-
- case Timaginary80:
- exp->type = Type::tfloat80;
- break;
-
- default:
- assert(0);
- }
- }
- else
- exp->type = t2; // t2 is complex
- }
- else if (t2->isimaginary())
- {
- exp->type = t1; // t1 is complex
- }
- }
- else if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- result = exp;
- }
-
- void visit(ModExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (exp->type->isfloating())
- {
- exp->type = exp->e1->type;
- if (exp->e2->type->iscomplex())
- {
- exp->error("cannot perform modulo complex arithmetic");
- return setError();
- }
- }
- result = exp;
- }
-
- void visit(PowExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- //printf("PowExp::semantic() %s\n", exp->toChars());
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- // For built-in numeric types, there are several cases.
- // TODO: backend support, especially for e1 ^^ 2.
-
- // First, attempt to fold the expression.
- e = exp->optimize(WANTvalue);
- if (e->op != TOKpow)
- {
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- // Determine if we're raising to an integer power.
- sinteger_t intpow = 0;
- if (exp->e2->op == TOKint64 && ((sinteger_t)exp->e2->toInteger() == 2 || (sinteger_t)exp->e2->toInteger() == 3))
- intpow = exp->e2->toInteger();
- else if (exp->e2->op == TOKfloat64 && (exp->e2->toReal() == ldouble((sinteger_t)exp->e2->toReal())))
- intpow = (sinteger_t)(exp->e2->toReal());
-
- // Deal with x^^2, x^^3 immediately, since they are of practical importance.
- if (intpow == 2 || intpow == 3)
- {
- // Replace x^^2 with (tmp = x, tmp*tmp)
- // Replace x^^3 with (tmp = x, tmp*tmp*tmp)
- VarDeclaration *tmp = copyToTemp(0, "__powtmp", exp->e1);
- Expression *de = new DeclarationExp(exp->loc, tmp);
- Expression *ve = new VarExp(exp->loc, tmp);
-
- /* Note that we're reusing ve. This should be ok.
- */
- Expression *me = new MulExp(exp->loc, ve, ve);
- if (intpow == 3)
- me = new MulExp(exp->loc, me, ve);
- e = new CommaExp(exp->loc, de, me);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- Module *mmath = loadStdMath();
- if (!mmath)
- {
- //exp->error("requires std.math for ^^ operators");
- //fatal();
-
- // Leave handling of PowExp to the backend, or throw
- // an error gracefully if no backend support exists.
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- result = exp;
- return;
- }
- e = new ScopeExp(exp->loc, mmath);
-
- if (exp->e2->op == TOKfloat64 && exp->e2->toReal() == CTFloat::half)
- {
- // Replace e1 ^^ 0.5 with .std.math.sqrt(x)
- e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_sqrt), exp->e1);
- }
- else
- {
- // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
- e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_pow), exp->e1, exp->e2);
- }
- e = expressionSemantic(e, sc);
- result = e;
- }
-
- void visit(ShlExp *exp)
- {
- //printf("ShlExp::semantic(), type = %p\n", exp->type);
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->checkIntegralBin())
- return setError();
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- exp->e1 = integralPromotions(exp->e1, sc);
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
-
- exp->type = exp->e1->type;
- result = exp;
- }
-
- void visit(ShrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->checkIntegralBin())
- return setError();
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- exp->e1 = integralPromotions(exp->e1, sc);
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
-
- exp->type = exp->e1->type;
- result = exp;
- }
-
- void visit(UshrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->checkIntegralBin())
- return setError();
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- exp->e1 = integralPromotions(exp->e1, sc);
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
-
- exp->type = exp->e1->type;
- result = exp;
- }
-
- void visit(AndExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->type->toBasetype()->ty == Tbool &&
- exp->e2->type->toBasetype()->ty == Tbool)
- {
- exp->type = exp->e1->type;
- result = exp;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->checkIntegralBin())
- return setError();
-
- result = exp;
- }
-
- void visit(OrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->type->toBasetype()->ty == Tbool &&
- exp->e2->type->toBasetype()->ty == Tbool)
- {
- exp->type = exp->e1->type;
- result = exp;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->checkIntegralBin())
- return setError();
-
- result = exp;
- }
-
- void visit(XorExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->type->toBasetype()->ty == Tbool &&
- exp->e2->type->toBasetype()->ty == Tbool)
- {
- exp->type = exp->e1->type;
- result = exp;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->checkIntegralBin())
- return setError();
-
- result = exp;
- }
-
- void visit(LogicalExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- Expression *e1x = expressionSemantic(exp->e1, sc);
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e1x->op == TOKtype)
- e1x = resolveAliasThis(sc, e1x);
-
- e1x = resolveProperties(sc, e1x);
- e1x = e1x->toBoolean(sc);
- unsigned cs1 = sc->callSuper;
-
- if (sc->flags & SCOPEcondition)
- {
- /* If in static if, don't evaluate e2 if we don't have to.
- */
- e1x = e1x->optimize(WANTvalue);
- if (e1x->isBool(exp->op == TOKoror))
- {
- result = new IntegerExp(exp->loc, exp->op == TOKoror, Type::tbool);
- return;
- }
- }
-
- Expression *e2x = expressionSemantic(exp->e2, sc);
- sc->mergeCallSuper(exp->loc, cs1);
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e2x->op == TOKtype)
- e2x = resolveAliasThis(sc, e2x);
-
- e2x = resolveProperties(sc, e2x);
-
- bool f1 = checkNonAssignmentArrayOp(e1x);
- bool f2 = checkNonAssignmentArrayOp(e2x);
- if (f1 || f2)
- return setError();
-
- // Unless the right operand is 'void', the expression is converted to 'bool'.
- if (e2x->type->ty != Tvoid)
- e2x = e2x->toBoolean(sc);
-
- if (e2x->op == TOKtype || e2x->op == TOKscope)
- {
- exp->error("%s is not an expression", exp->e2->toChars());
- return setError();
- }
- if (e1x->op == TOKerror || e1x->type->ty == Tnoreturn)
- {
- result = e1x;
- return;
- }
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
-
- // The result type is 'bool', unless the right operand has type 'void'.
- if (e2x->type->ty == Tvoid)
- exp->type = Type::tvoid;
- else
- exp->type = Type::tbool;
-
- exp->e1 = e1x;
- exp->e2 = e2x;
- result = exp;
- }
-
- void visit(InExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *t2b = exp->e2->type->toBasetype();
- switch (t2b->ty)
- {
- case Taarray:
- {
- TypeAArray *ta = (TypeAArray *)t2b;
-
- // Special handling for array keys
- if (!arrayTypeCompatible(exp->e1->loc, exp->e1->type, ta->index))
- {
- // Convert key to type of key
- exp->e1 = exp->e1->implicitCastTo(sc, ta->index);
- }
-
- semanticTypeInfo(sc, ta->index);
-
- // Return type is pointer to value
- exp->type = ta->nextOf()->pointerTo();
- break;
- }
-
- default:
- result = exp->incompatibleTypes();
- return;
-
- case Terror:
- return setError();
- }
- result = exp;
- }
-
- void visit(RemoveExp *e)
- {
- if (Expression *ex = binSemantic(e, sc))
- {
- result = ex;
- return;
- }
- result = e;
- }
-
- void visit(CmpExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
- if ((t1->ty == Tclass && exp->e2->op == TOKnull) ||
- (t2->ty == Tclass && exp->e1->op == TOKnull))
- {
- exp->error("do not use null when comparing class types");
- return setError();
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- if (!e->type->isscalar() && e->type->equals(exp->e1->type))
- {
- exp->error("recursive opCmp expansion");
- return setError();
- }
- if (e->op == TOKcall)
- {
- e = new CmpExp(exp->op, exp->loc, e, new IntegerExp(exp->loc, 0, Type::tint32));
- e = expressionSemantic(e, sc);
- }
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- exp->type = Type::tbool;
-
- // Special handling for array comparisons
- t1 = exp->e1->type->toBasetype();
- t2 = exp->e2->type->toBasetype();
- if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
- (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
- {
- Type *t1next = t1->nextOf();
- Type *t2next = t2->nextOf();
- if (t1next->implicitConvTo(t2next) < MATCHconst &&
- t2next->implicitConvTo(t1next) < MATCHconst &&
- (t1next->ty != Tvoid && t2next->ty != Tvoid))
- {
- exp->error("array comparison type mismatch, %s vs %s", t1next->toChars(), t2next->toChars());
- return setError();
- }
- if ((t1->ty == Tarray || t1->ty == Tsarray) &&
- (t2->ty == Tarray || t2->ty == Tsarray))
- {
- semanticTypeInfo(sc, t1->nextOf());
- }
- }
- else if (t1->ty == Tstruct || t2->ty == Tstruct ||
- (t1->ty == Tclass && t2->ty == Tclass))
- {
- if (t2->ty == Tstruct)
- exp->error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars());
- else
- exp->error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars());
- return setError();
- }
- else if (t1->iscomplex() || t2->iscomplex())
- {
- exp->error("compare not defined for complex operands");
- return setError();
- }
- else if (t1->ty == Taarray || t2->ty == Taarray)
- {
- exp->error("%s is not defined for associative arrays", Token::toChars(exp->op));
- return setError();
- }
- else if (!target.isVectorOpSupported(t1, exp->op, t2))
- {
- result = exp->incompatibleTypes();
- return;
- }
- else
- {
- bool r1 = exp->e1->checkValue();
- bool r2 = exp->e2->checkValue();
- if (r1 || r2)
- return setError();
- }
-
- TOK altop;
- switch (exp->op)
- {
- // Refer rel_integral[] table
- case TOKunord: altop = TOKerror; break;
- case TOKlg: altop = TOKnotequal; break;
- case TOKleg: altop = TOKerror; break;
- case TOKule: altop = TOKle; break;
- case TOKul: altop = TOKlt; break;
- case TOKuge: altop = TOKge; break;
- case TOKug: altop = TOKgt; break;
- case TOKue: altop = TOKequal; break;
- default: altop = TOKreserved; break;
- }
- if (altop == TOKerror &&
- (t1->ty == Tarray || t1->ty == Tsarray ||
- t2->ty == Tarray || t2->ty == Tsarray))
- {
- exp->error("`%s` is not defined for array comparisons", Token::toChars(exp->op));
- return setError();
- }
- if (altop != TOKreserved)
- {
- if (!t1->isfloating())
- {
- if (altop == TOKerror)
- {
- const char *s = exp->op == TOKunord ? "false" : "true";
- exp->error("floating point operator `%s` always returns %s for non-floating comparisons",
- Token::toChars(exp->op), s);
- }
- else
- {
- exp->error("use `%s` for non-floating comparisons rather than floating point operator `%s`",
- Token::toChars(altop), Token::toChars(exp->op));
- }
- }
- else
- {
- exp->error("use std.math.isNaN to deal with NaN operands rather than floating point operator `%s`",
- Token::toChars(exp->op));
- }
- return setError();
- }
-
- //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars());
- result = exp;
- }
-
- void visit(EqualExp *exp)
- {
- //printf("EqualExp::semantic('%s')\n", toChars());
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- if (Expression *e = binSemanticProp(exp, sc))
- {
- result = e;
- return;
- }
- if (exp->e1->op == TOKtype || exp->e2->op == TOKtype)
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- {
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
- if (t1->ty == Tenum && t2->ty == Tenum && !t1->equivalent(t2))
- exp->deprecation("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
- t1->toChars(), t2->toChars());
- }
-
- /* Before checking for operator overloading, check to see if we're
- * comparing the addresses of two statics. If so, we can just see
- * if they are the same symbol.
- */
- if (exp->e1->op == TOKaddress && exp->e2->op == TOKaddress)
- {
- AddrExp *ae1 = (AddrExp *)exp->e1;
- AddrExp *ae2 = (AddrExp *)exp->e2;
- if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar)
- {
- VarExp *ve1 = (VarExp *)ae1->e1;
- VarExp *ve2 = (VarExp *)ae2->e1;
-
- if (ve1->var == ve2->var)
- {
- // They are the same, result is 'true' for ==, 'false' for !=
- result = new IntegerExp(exp->loc, (exp->op == TOKequal), Type::tbool);
- return;
- }
- }
- }
-
- if (Expression *e = exp->op_overload(sc))
- {
- result = e;
- return;
- }
-
- if (Expression *e = typeCombine(exp, sc))
- {
- result = e;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- exp->type = Type::tbool;
-
- // Special handling for array comparisons
- if (!arrayTypeCompatible(exp->loc, exp->e1->type, exp->e2->type))
- {
- if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
- {
- // Cast both to complex
- exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
- exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
- }
- }
- if (exp->e1->type->toBasetype()->ty == Taarray)
- semanticTypeInfo(sc, exp->e1->type->toBasetype());
-
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
-
- if (!target.isVectorOpSupported(t1, exp->op, t2))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- result = exp;
- }
-
- void visit(IdentityExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- if (exp->e1->op == TOKtype || exp->e2->op == TOKtype)
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- exp->type = Type::tbool;
-
- if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
- {
- // Cast both to complex
- exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
- exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
- }
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
- if (!target.isVectorOpSupported(tb1, exp->op, tb2))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- result = exp;
- }
-
- void visit(CondExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (exp->econd->op == TOKdotid)
- ((DotIdExp *)exp->econd)->noderef = true;
-
- Expression *ec = expressionSemantic(exp->econd, sc);
- ec = resolveProperties(sc, ec);
- ec = ec->toBoolean(sc);
-
- unsigned cs0 = sc->callSuper;
- unsigned *fi0 = sc->saveFieldInit();
- Expression *e1x = expressionSemantic(exp->e1, sc);
- e1x = resolveProperties(sc, e1x);
-
- unsigned cs1 = sc->callSuper;
- unsigned *fi1 = sc->fieldinit;
- sc->callSuper = cs0;
- sc->fieldinit = fi0;
- Expression *e2x = expressionSemantic(exp->e2, sc);
- e2x = resolveProperties(sc, e2x);
-
- sc->mergeCallSuper(exp->loc, cs1);
- sc->mergeFieldInit(exp->loc, fi1);
-
- if (ec->op == TOKerror)
- {
- result = ec;
- return;
- }
- if (ec->type == Type::terror)
- return setError();
- exp->econd = ec;
-
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- if (e1x->type == Type::terror)
- return setError();
- exp->e1 = e1x;
-
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- if (e2x->type == Type::terror)
- return setError();
- exp->e2 = e2x;
-
- bool f0 = checkNonAssignmentArrayOp(exp->econd);
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f0 || f1 || f2)
- return setError();
-
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
- if (t1->ty == Tnoreturn)
- {
- exp->type = t2;
- }
- else if (t2->ty == Tnoreturn)
- {
- exp->type = t1;
- }
- // If either operand is void the result is void, we have to cast both
- // the expression to void so that we explicitly discard the expression
- // value if any (bugzilla 16598)
- else if (t1->ty == Tvoid || t2->ty == Tvoid)
- {
- exp->type = Type::tvoid;
- exp->e1 = exp->e1->castTo(sc, exp->type);
- exp->e2 = exp->e2->castTo(sc, exp->type);
- }
- else if (t1 == t2)
- exp->type = t1;
- else
- {
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- switch (exp->e1->type->toBasetype()->ty)
- {
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- exp->e2 = exp->e2->castTo(sc, exp->e1->type);
- break;
- }
- switch (exp->e2->type->toBasetype()->ty)
- {
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- exp->e1 = exp->e1->castTo(sc, exp->e2->type);
- break;
- }
- if (exp->type->toBasetype()->ty == Tarray)
- {
- exp->e1 = exp->e1->castTo(sc, exp->type);
- exp->e2 = exp->e2->castTo(sc, exp->type);
- }
- }
- exp->type = exp->type->merge2();
-
- /* Bugzilla 14696: If either e1 or e2 contain temporaries which need dtor,
- * make them conditional.
- * Rewrite:
- * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
- * to:
- * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
- * and replace edtors of __tmp1 and __tmp2 with:
- * __tmp1->edtor --> __cond && __tmp1.dtor()
- * __tmp2->edtor --> __cond || __tmp2.dtor()
- */
- exp->hookDtors(sc);
-
- result = exp;
- }
-
- void visit(FileInitExp *e)
- {
- //printf("FileInitExp::semantic()\n");
- e->type = Type::tstring;
- result = e;
- }
-
- void visit(LineInitExp *e)
- {
- e->type = Type::tint32;
- result = e;
- }
-
- void visit(ModuleInitExp *e)
- {
- //printf("ModuleInitExp::semantic()\n");
- e->type = Type::tstring;
- result = e;
- }
-
- void visit(FuncInitExp *e)
- {
- //printf("FuncInitExp::semantic()\n");
- e->type = Type::tstring;
- if (sc->func)
- {
- result = e->resolveLoc(Loc(), sc);
- return;
- }
- result = e;
- }
-
- void visit(PrettyFuncInitExp *e)
- {
- //printf("PrettyFuncInitExp::semantic()\n");
- e->type = Type::tstring;
- if (sc->func)
- {
- result = e->resolveLoc(Loc(), sc);
- return;
- }
- result = e;
- }
-};
-
-/**********************************
- * Try to run semantic routines.
- * If they fail, return NULL.
- */
-Expression *trySemantic(Expression *exp, Scope* sc)
-{
- //printf("+trySemantic(%s)\n", toChars());
- unsigned errors = global.startGagging();
- Expression *e = expressionSemantic(exp, sc);
- if (global.endGagging(errors))
- {
- e = NULL;
- }
- //printf("-trySemantic(%s)\n", toChars());
- return e;
-}
-
-/**************************
- * Helper function for easy error propagation.
- * If error occurs, returns ErrorExp. Otherwise returns NULL.
- */
-Expression *unaSemantic(UnaExp *e, Scope *sc)
-{
- Expression *e1x = expressionSemantic(e->e1, sc);
- if (e1x->op == TOKerror)
- return e1x;
- e->e1 = e1x;
- return NULL;
-}
-
-/**************************
- * Helper function for easy error propagation.
- * If error occurs, returns ErrorExp. Otherwise returns NULL.
- */
-Expression *binSemantic(BinExp *e, Scope *sc)
-{
- Expression *e1x = expressionSemantic(e->e1, sc);
- Expression *e2x = expressionSemantic(e->e2, sc);
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e1x->op == TOKtype)
- e1x = resolveAliasThis(sc, e1x);
- if (e2x->op == TOKtype)
- e2x = resolveAliasThis(sc, e2x);
-
- if (e1x->op == TOKerror)
- return e1x;
- if (e2x->op == TOKerror)
- return e2x;
- e->e1 = e1x;
- e->e2 = e2x;
- return NULL;
-}
-
-Expression *binSemanticProp(BinExp *e, Scope *sc)
-{
- if (Expression *ex = binSemantic(e, sc))
- return ex;
- Expression *e1x = resolveProperties(sc, e->e1);
- Expression *e2x = resolveProperties(sc, e->e2);
- if (e1x->op == TOKerror)
- return e1x;
- if (e2x->op == TOKerror)
- return e2x;
- e->e1 = e1x;
- e->e2 = e2x;
- return NULL;
-}
-
-// entrypoint for semantic ExpressionSemanticVisitor
-Expression *expressionSemantic(Expression *e, Scope *sc)
-{
- ExpressionSemanticVisitor v = ExpressionSemanticVisitor(sc);
- e->accept(&v);
- return v.result;
-}
-
-Expression *semanticX(DotIdExp *exp, Scope *sc)
-{
- //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
- if (Expression *ex = unaSemantic(exp, sc))
- return ex;
-
- if (exp->ident == Id::_mangleof)
- {
- // symbol.mangleof
- Dsymbol *ds;
- switch (exp->e1->op)
- {
- case TOKscope:
- ds = ((ScopeExp *)exp->e1)->sds;
- goto L1;
- case TOKvar:
- ds = ((VarExp *)exp->e1)->var;
- goto L1;
- case TOKdotvar:
- ds = ((DotVarExp *)exp->e1)->var;
- goto L1;
- case TOKoverloadset:
- ds = ((OverExp *)exp->e1)->vars;
- goto L1;
- case TOKtemplate:
- {
- TemplateExp *te = (TemplateExp *)exp->e1;
- ds = te->fd ? (Dsymbol *)te->fd : te->td;
- }
- L1:
- {
- assert(ds);
- if (FuncDeclaration *f = ds->isFuncDeclaration())
- {
- if (f->checkForwardRef(exp->loc))
- return new ErrorExp();
- }
- OutBuffer buf;
- mangleToBuffer(ds, &buf);
- const char *s = buf.extractChars();
- Expression *e = new StringExp(exp->loc, const_cast<char*>(s), strlen(s));
- e = expressionSemantic(e, sc);
- return e;
- }
- default:
- break;
- }
- }
-
- if (exp->e1->op == TOKvar && exp->e1->type->toBasetype()->ty == Tsarray && exp->ident == Id::length)
- {
- // bypass checkPurity
- return exp->e1->type->dotExp(sc, exp->e1, exp->ident, exp->noderef ? 2 : 0);
- }
-
- if (exp->e1->op == TOKdot)
- {
- }
- else
- {
- exp->e1 = resolvePropertiesX(sc, exp->e1);
- }
- if (exp->e1->op == TOKtuple && exp->ident == Id::offsetof)
- {
- /* 'distribute' the .offsetof to each of the tuple elements.
- */
- TupleExp *te = (TupleExp *)exp->e1;
- Expressions *exps = new Expressions();
- exps->setDim(te->exps->length);
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*te->exps)[i];
- e = expressionSemantic(e, sc);
- e = new DotIdExp(e->loc, e, Id::offsetof);
- (*exps)[i] = e;
- }
- // Don't evaluate te->e0 in runtime
- Expression *e = new TupleExp(exp->loc, NULL, exps);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (exp->e1->op == TOKtuple && exp->ident == Id::length)
- {
- TupleExp *te = (TupleExp *)exp->e1;
- // Don't evaluate te->e0 in runtime
- Expression *e = new IntegerExp(exp->loc, te->exps->length, Type::tsize_t);
- return e;
- }
-
- // Bugzilla 14416: Template has no built-in properties except for 'stringof'.
- if ((exp->e1->op == TOKdottd || exp->e1->op == TOKtemplate) && exp->ident != Id::stringof)
- {
- exp->error("template %s does not have property `%s`", exp->e1->toChars(), exp->ident->toChars());
- return new ErrorExp();
- }
-
- if (!exp->e1->type)
- {
- exp->error("expression %s does not have property `%s`", exp->e1->toChars(), exp->ident->toChars());
- return new ErrorExp();
- }
-
- return exp;
-}
-
-// Resolve e1.ident without seeing UFCS.
-// If flag == 1, stop "not a property" error and return NULL.
-Expression *semanticY(DotIdExp *exp, Scope *sc, int flag)
-{
- //printf("DotIdExp::semanticY(this = %p, '%s')\n", this, toChars());
-
- //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
-
- /* Special case: rewrite this.id and super.id
- * to be classtype.id and baseclasstype.id
- * if we have no this pointer.
- */
- if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && !hasThis(sc))
- {
- if (AggregateDeclaration *ad = sc->getStructClassScope())
- {
- if (exp->e1->op == TOKthis)
- {
- exp->e1 = new TypeExp(exp->e1->loc, ad->type);
- }
- else
- {
- ClassDeclaration *cd = ad->isClassDeclaration();
- if (cd && cd->baseClass)
- exp->e1 = new TypeExp(exp->e1->loc, cd->baseClass->type);
- }
- }
- }
-
- Expression *e = semanticX(exp, sc);
- if (e != exp)
- return e;
-
- Expression *eleft;
- Expression *eright;
- if (exp->e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)exp->e1;
- eleft = de->e1;
- eright = de->e2;
- }
- else
- {
- eleft = NULL;
- eright = exp->e1;
- }
-
- Type *t1b = exp->e1->type->toBasetype();
-
- if (eright->op == TOKscope) // also used for template alias's
- {
- ScopeExp *ie = (ScopeExp *)eright;
- int flags = SearchLocalsOnly;
-
- /* Disable access to another module's private imports.
- * The check for 'is sds our current module' is because
- * the current module should have access to its own imports.
- */
- if (ie->sds->isModule() && ie->sds != sc->_module)
- flags |= IgnorePrivateImports;
- if (sc->flags & SCOPEignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
- Dsymbol *s = ie->sds->search(exp->loc, exp->ident, flags);
- /* Check for visibility before resolving aliases because public
- * aliases to private symbols are public.
- */
- if (s && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc->_module, s))
- {
- s = NULL;
- }
- if (s)
- {
- Package *p = s->isPackage();
- if (p && checkAccess(sc, p))
- {
- s = NULL;
- }
- }
- if (s)
- {
- // if 's' is a tuple variable, the tuple is returned.
- s = s->toAlias();
-
- exp->checkDeprecated(sc, s);
- exp->checkDisabled(sc, s);
-
- EnumMember *em = s->isEnumMember();
- if (em)
- {
- return em->getVarExp(exp->loc, sc);
- }
-
- VarDeclaration *v = s->isVarDeclaration();
- if (v)
- {
- //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
- if (!v->type ||
- (!v->type->deco && v->inuse))
- {
- if (v->inuse)
- exp->error("circular reference to %s `%s`", v->kind(), v->toPrettyChars());
- else
- exp->error("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 && !exp->wantsym)
- {
- /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
- * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
- * be reverted. `wantsym` is the hack to work around the problem.
- */
- if (v->inuse)
- {
- ::error(exp->loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- e = v->expandInitializer(exp->loc);
- v->inuse++;
- e = expressionSemantic(e, sc);
- v->inuse--;
- return e;
- }
-
- if (v->needThis())
- {
- if (!eleft)
- eleft = new ThisExp(exp->loc);
- e = new DotVarExp(exp->loc, eleft, v);
- e = expressionSemantic(e, sc);
- }
- else
- {
- e = new VarExp(exp->loc, v);
- if (eleft)
- { e = new CommaExp(exp->loc, eleft, e);
- e->type = v->type;
- }
- }
- e = e->deref();
- return expressionSemantic(e, sc);
- }
-
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- //printf("it's a function\n");
- if (!f->functionSemantic())
- return new ErrorExp();
- if (f->needThis())
- {
- if (!eleft)
- eleft = new ThisExp(exp->loc);
- e = new DotVarExp(exp->loc, eleft, f, true);
- e = expressionSemantic(e, sc);
- }
- else
- {
- e = new VarExp(exp->loc, f, true);
- if (eleft)
- { e = new CommaExp(exp->loc, eleft, e);
- e->type = f->type;
- }
- }
- return e;
- }
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- if (eleft)
- e = new DotTemplateExp(exp->loc, eleft, td);
- else
- e = new TemplateExp(exp->loc, td);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (OverDeclaration *od = s->isOverDeclaration())
- {
- e = new VarExp(exp->loc, od, true);
- if (eleft)
- {
- e = new CommaExp(exp->loc, eleft, e);
- e->type = Type::tvoid; // ambiguous type?
- }
- return e;
- }
- OverloadSet *o = s->isOverloadSet();
- if (o)
- { //printf("'%s' is an overload set\n", o->toChars());
- return new OverExp(exp->loc, o);
- }
-
- if (Type *t = s->getType())
- {
- return expressionSemantic(new TypeExp(exp->loc, t), sc);
- }
-
- TupleDeclaration *tup = s->isTupleDeclaration();
- if (tup)
- {
- if (eleft)
- {
- e = new DotVarExp(exp->loc, eleft, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new TupleExp(exp->loc, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- ScopeDsymbol *sds = s->isScopeDsymbol();
- if (sds)
- {
- //printf("it's a ScopeDsymbol %s\n", exp->ident->toChars());
- e = new ScopeExp(exp->loc, sds);
- e = expressionSemantic(e, sc);
- if (eleft)
- e = new DotExp(exp->loc, eleft, e);
- return e;
- }
-
- Import *imp = s->isImport();
- if (imp)
- {
- ie = new ScopeExp(exp->loc, imp->pkg);
- return expressionSemantic(ie, sc);
- }
-
- // BUG: handle other cases like in IdentifierExp::semantic()
- assert(0);
- }
- else if (exp->ident == Id::stringof)
- {
- const char *p = ie->toChars();
- e = new StringExp(exp->loc, const_cast<char *>(p), strlen(p));
- e = expressionSemantic(e, sc);
- return e;
- }
- if (ie->sds->isPackage() ||
- ie->sds->isImport() ||
- ie->sds->isModule())
- {
- flag = 0;
- }
- if (flag)
- return NULL;
- s = ie->sds->search_correct(exp->ident);
- if (s)
- {
- if (s->isPackage())
- exp->error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`",
- exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->toPrettyChars());
- else
- exp->error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?",
- exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->kind(), s->toChars());
- }
- else
- exp->error("undefined identifier `%s` in %s `%s`",
- exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars());
- return new ErrorExp();
- }
- else if (t1b->ty == Tpointer && exp->e1->type->ty != Tenum &&
- exp->ident != Id::_init && exp->ident != Id::__sizeof &&
- exp->ident != Id::__xalignof && exp->ident != Id::offsetof &&
- exp->ident != Id::_mangleof && exp->ident != Id::stringof)
- {
- Type *t1bn = t1b->nextOf();
- if (flag)
- {
- AggregateDeclaration *ad = isAggregate(t1bn);
- if (ad && !ad->members) // Bugzilla 11312
- return NULL;
- }
-
- /* Rewrite:
- * p.ident
- * as:
- * (*p).ident
- */
- if (flag && t1bn->ty == Tvoid)
- return NULL;
- e = new PtrExp(exp->loc, exp->e1);
- e = expressionSemantic(e, sc);
- return e->type->dotExp(sc, e, exp->ident, flag | (exp->noderef ? 2 : 0));
- }
- else
- {
- if (exp->e1->op == TOKtype || exp->e1->op == TOKtemplate)
- flag = 0;
- e = exp->e1->type->dotExp(sc, exp->e1, exp->ident, flag | (exp->noderef ? 2 : 0));
- if (e)
- e = expressionSemantic(e, sc);
- return e;
- }
-}
-
-// Resolve e1.ident!tiargs without seeing UFCS.
-// If flag == 1, stop "not a property" error and return NULL.
-Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag)
-{
- DotIdExp *die = new DotIdExp(exp->loc, exp->e1, exp->ti->name);
-
- Expression *e = semanticX(die, sc);
- if (e == die)
- {
- exp->e1 = die->e1; // take back
-
- Type *t1b = exp->e1->type->toBasetype();
- if (t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Taarray ||
- t1b->ty == Tnull || (t1b->isTypeBasic() && t1b->ty != Tvoid))
- {
- /* No built-in type has templatized properties, so do shortcut.
- * It is necessary in: 1024.max!"a < b"
- */
- if (flag)
- return NULL;
- }
- e = semanticY(die, sc, flag);
- if (flag && e && isDotOpDispatch(e))
- {
- /* opDispatch!tiargs would be a function template that needs IFTI,
- * so it's not a template
- */
- e = NULL; /* fall down to UFCS */
- }
- if (flag && !e)
- return NULL;
- }
- assert(e);
-
- if (e->op == TOKerror)
- return e;
- if (e->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)e;
- if (FuncDeclaration *fd = dve->var->isFuncDeclaration())
- {
- TemplateDeclaration *td = fd->findTemplateDeclRoot();
- if (td)
- {
- e = new DotTemplateExp(dve->loc, dve->e1, td);
- e = expressionSemantic(e, sc);
- }
- }
- else if (dve->var->isOverDeclaration())
- {
- exp->e1 = dve->e1; // pull semantic() result
- if (!exp->findTempDecl(sc))
- goto Lerr;
- if (exp->ti->needsTypeInference(sc))
- return exp;
- dsymbolSemantic(exp->ti, sc);
- if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
- return new ErrorExp();
- Dsymbol *s = exp->ti->toAlias();
- Declaration *v = s->isDeclaration();
- if (v)
- {
- if (v->type && !v->type->deco)
- v->type = typeSemantic(v->type, v->loc, sc);
- e = new DotVarExp(exp->loc, exp->e1, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new ScopeExp(exp->loc, exp->ti);
- e = new DotExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- else if (e->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e;
- if (FuncDeclaration *fd = ve->var->isFuncDeclaration())
- {
- TemplateDeclaration *td = fd->findTemplateDeclRoot();
- if (td)
- {
- e = new TemplateExp(ve->loc, td);
- e = expressionSemantic(e, sc);
- }
- }
- else if (OverDeclaration *od = ve->var->isOverDeclaration())
- {
- exp->ti->tempdecl = od;
- e = new ScopeExp(exp->loc, exp->ti);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- if (e->op == TOKdottd)
- {
- DotTemplateExp *dte = (DotTemplateExp *)e;
- exp->e1 = dte->e1; // pull semantic() result
-
- exp->ti->tempdecl = dte->td;
- if (!exp->ti->semanticTiargs(sc))
- return new ErrorExp();
- if (exp->ti->needsTypeInference(sc))
- return exp;
- dsymbolSemantic(exp->ti, sc);
- if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
- return new ErrorExp();
- Dsymbol *s = exp->ti->toAlias();
- Declaration *v = s->isDeclaration();
- if (v && (v->isFuncDeclaration() || v->isVarDeclaration()))
- {
- e = new DotVarExp(exp->loc, exp->e1, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new ScopeExp(exp->loc, exp->ti);
- e = new DotExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- return e;
- }
- else if (e->op == TOKtemplate)
- {
- exp->ti->tempdecl = ((TemplateExp *)e)->td;
- e = new ScopeExp(exp->loc, exp->ti);
- e = expressionSemantic(e, sc);
- return e;
- }
- else if (e->op == TOKdot)
- {
- DotExp *de = (DotExp *)e;
-
- if (de->e2->op == TOKoverloadset)
- {
- if (!exp->findTempDecl(sc) ||
- !exp->ti->semanticTiargs(sc))
- {
- return new ErrorExp();
- }
- if (exp->ti->needsTypeInference(sc))
- return exp;
- dsymbolSemantic(exp->ti, sc);
- if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
- return new ErrorExp();
- Dsymbol *s = exp->ti->toAlias();
- Declaration *v = s->isDeclaration();
- if (v)
- {
- if (v->type && !v->type->deco)
- v->type = typeSemantic(v->type, v->loc, sc);
- e = new DotVarExp(exp->loc, exp->e1, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new ScopeExp(exp->loc, exp->ti);
- e = new DotExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- else if (e->op == TOKoverloadset)
- {
- OverExp *oe = (OverExp *)e;
- exp->ti->tempdecl = oe->vars;
- e = new ScopeExp(exp->loc, exp->ti);
- e = expressionSemantic(e, sc);
- return e;
- }
-Lerr:
- e->error("%s isn't a template", e->toChars());
- return new ErrorExp();
-}