diff options
Diffstat (limited to 'gcc/d/dmd/expressionsem.c')
-rw-r--r-- | gcc/d/dmd/expressionsem.c | 10740 |
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(); -} |