blob: 847a079679269c891adcdb86befbaeafda7dd827 [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2019 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);
TypeTuple *toArgTypes(Type *t);
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);
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);
bool MODimplicitConv(MOD modfrom, MOD modto);
MATCH MODmethodConv(MOD modfrom, MOD modto);
void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
void unSpeculative(Scope *sc, RootObject *o);
bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt);
bool checkDefCtor(Loc loc, Type *t);
bool isDotOpDispatch(Expression *e);
bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix);
Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, Expression *e1, Declaration *var, int flag = 0);
bool isNeedThisScope(Scope *sc, Declaration *d);
Expression *resolveUFCS(Scope *sc, CallExp *ce);
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);
Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL);
Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL);
Expression *trySemantic(Expression *e, Scope *sc);
Expression *unaSemantic(UnaExp *e, Scope *sc);
Expression *binSemantic(BinExp *e, Scope *sc);
Expression *binSemanticProp(BinExp *e, Scope *sc);
Expression *semantic(Expression *e, Scope *sc);
Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
/****************************************
* 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->dim; 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;
}
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.dim; 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 = e->type->semantic(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 = e->type->semantic(e->loc, sc);
result = e;
}
void visit(ComplexExp *e)
{
if (!e->type)
e->type = Type::tcomplex80;
else
e->type = e->type->semantic(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)
{
/* 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 = semantic(e, sc);
}
else
{
if (withsym)
{
Declaration *d = s->isDeclaration();
if (d)
checkAccess(exp->loc, sc, NULL, d);
}
/* 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 = semantic(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;
Expression *e = new VarExp(exp->loc, vd);
e = semantic(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 = e->type->semantic(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 = semantic(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 = e->type->semantic(e->loc, sc);
/* Disallow array literals of type void being used.
*/
if (e->elements->dim > 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->dim != e->values->dim)
{
e->error("number of keys is %u, must match number of values %u", e->keys->dim, e->values->dim);
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 = e->type->semantic(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->dim))
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)
{
//printf("e = %s %s\n", Token::toChars(e->op), e->toChars());
e = semantic(e, sc);
}
else if (t)
{
//printf("t = %d %s\n", t->ty, t->toChars());
exp->type = t->semantic(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 = semantic(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 = semantic(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 = semantic(e, sc);
return;
}
}
// ti is an instance which requires IFTI.
exp->sds = ti;
exp->type = Type::tvoid;
result = exp;
return;
}
ti->semantic(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 = semantic(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());
sds2->semantic(sc);
if (Type *t = sds2->getType()) // (Aggregate|Enum)Declaration
{
Expression *ex = new TypeExp(exp->loc, t);
result = semantic(ex, sc);
return;
}
if (TemplateDeclaration *td = sds2->isTemplateDeclaration())
{
result = semantic(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 = semantic(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 = exp->newtype->semantic(exp->loc, sc);
sc = sc->pop();
}
else
{
exp->type = exp->newtype->semantic(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 = exp->type->semantic(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->dim : 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.dim; 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 = semantic(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->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->dim)
{
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->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();
}
}
}
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->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->dim)
{
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->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.dim))
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->dim : 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 = semantic(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 = semantic(c, sc);
}
void visit(SymOffExp *e)
{
//var->semantic(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)
{
if (FuncDeclaration *fd = e->var->isFuncDeclaration())
{
//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)
e->type = e->type->semantic(e->loc, sc);
/* 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 (VarDeclaration *vd = e->var->isVarDeclaration())
{
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 (FuncDeclaration *fd = e->var->isFuncDeclaration())
{
// 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 = semantic(exp->e0, sc);
// Run semantic() on each argument
bool err = false;
for (size_t i = 0; i < exp->exps->dim; i++)
{
Expression *e = (*exp->exps)[i];
e = semantic(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 = exp->type->semantic(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(PROTpublic); // 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 = exp->fd->treq->semantic(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->dim);
exp->td->semantic(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;
exp->fd->semantic(sc);
if (olderrors == global.errors)
{
exp->fd->semantic2(sc);
if (olderrors == global.errors)
exp->fd->semantic3(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 = exp->type->semantic(exp->loc, sc);
exp->fd->tok = TOKdelegate;
}
else
{
exp->type = new TypePointer(exp->fd->type);
exp->type = exp->type->semantic(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->dim)
{
for (size_t k = 0; k < arguments->dim; k++)
{ Expression *checkarg = (*arguments)[k];
if (checkarg->op == TOKerror)
return checkarg;
}
exp->genIdent(sc);
assert(exp->td->parameters && exp->td->parameters->dim);
exp->td->semantic(sc);
TypeFunction *tfl = (TypeFunction *)exp->fd->type;
size_t dim = Parameter::dim(tfl->parameters);
if (arguments->dim < dim)
{ // Default arguments are always typed, so they don't need inference.
Parameter *p = Parameter::getNth(tfl->parameters, arguments->dim);
if (p->defaultArg)
dim = arguments->dim;
}
if ((!tfl->varargs && arguments->dim == dim) ||
( tfl->varargs && arguments->dim >= dim))
{
Objects *tiargs = new Objects();
tiargs->reserve(exp->td->parameters->dim);
for (size_t i = 0; i < exp->td->parameters->dim; i++)
{
TemplateParameter *tp = (*exp->td->parameters)[i];
for (size_t u = 0; u < dim; u++)
{ Parameter *p = Parameter::getNth(tfl->parameters, 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 semantic(se, sc);
}
exp->error("cannot infer function literal type");
return new ErrorExp();
}
return semantic(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->dim == 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.
e->declaration->semantic(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 = scx->enclosing)
{
Dsymbol *s2;
if (scx->scopesym && scx->scopesym->symtab &&
(s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
s != s2)
{
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);
e->declaration->semantic(sc2);
if (sc2 != sc)
sc2->pop();
s->parent = sc->parent;
}
if (global.errors == olderrors)
{
e->declaration->semantic2(sc);
if (global.errors == olderrors)
{
e->declaration->semantic3(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 = semantic(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 = semantic(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 = semantic(e, sc);
}
}
result = e;
}
void visit(TraitsExp *e)
{
result = semanticTraits(e, sc);
}
void visit(HaltExp *e)
{
e->type = Type::tvoid;
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;
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)
goto Lno; // errors, so condition is false
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->dim);
if (cd->_scope && !cd->symtab)
cd->semantic(cd->_scope);
for (size_t i = 0; i < cd->baseclasses->dim; i++)
{
BaseClass *b = (*cd->baseclasses)[i];
args->push(new Parameter(STCin, b->type, 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);
Parameters *params = ((TypeFunction *)tded)->parameters;
size_t dim = Parameter::dim(params);
Parameters *args = new Parameters;
args->reserve(dim);
for (size_t i = 0; i < dim; i++)
{
Parameter *arg = Parameter::getNth(params, 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));
}
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 = 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->dim))
{
/* Evaluate to true if targ matches tspec
* is(targ == tspec)
* is(targ : tspec)
*/
e->tspec = e->tspec->semantic(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->dim);
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->dim; 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;
s->semantic(sc);
if (sc->sds)
s->addMember(sc, sc->sds);
else 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);
s->semantic(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());
if (sc->sds)
s->addMember(sc, sc->sds);
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 = ArrayLengthExp::rewriteOpAssign(exp);
e = semantic(e, sc);
result = e;
return;
}
if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
{
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 = semantic(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);
}
void visit(CompileExp *exp)
{
StringExp *se = semanticString(sc, exp->e1, "argument to mixin");
if (!se)
return setError();
se = se->toUTF8(sc);
unsigned errors = global.errors;
Parser p(exp->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
Expression *e = p.parseExpression();
if (p.errors)
{
assert(global.errors != errors); // should have caught all these cases
return setError();
}
if (p.token.value != TOKeof)
{
exp->error("incomplete mixin expression (%s)", se->toChars());
return setError();
}
result = semantic(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();
}
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)
ob->writestring("depsFile ");
ob->writestring(imod->toPrettyChars());
ob->writestring(" (");
escapePath(ob, imod->srcfile->toChars());
ob->writestring(") : ");
if (global.params.moduleDepsFile)
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 = semantic(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 = semantic(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))
{
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)
{
Expression *e = new HaltExp(exp->loc);
e = semantic(e, sc);
result = e;
return;
}
}
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 (Expression *ex = unaSemantic(e, sc))
{
result = ex;
return;
}
result = e;
}
void visit(DotVarExp *exp)
{
if (exp->type)
{
result = exp;
return;
}
exp->var = exp->var->toAlias()->isDeclaration();
exp->e1 = semantic(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->dim);
for (size_t i = 0; i < tup->objects->dim; 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 = semantic(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 = semantic(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 = semantic(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 = semantic(e->e1, sc);
e->type = new TypeDelegate(e->func->type);
e->type = e->type->semantic(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.peekString(), f->toPrettyChars(), thisBuf.peekString(), 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 = semantic(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 = semantic(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 = semantic(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,