Merge dmd-1.074 into ldc.

This commit is contained in:
kai
2012-04-13 21:07:31 +02:00
parent f1998a6110
commit 1c6ff32d50
54 changed files with 5533 additions and 4034 deletions

View File

@@ -27,7 +27,6 @@
#include "attrib.h" // for AttribDeclaration
#include "template.h"
TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd);
#define LOG 0
@@ -45,6 +44,10 @@ private:
together with the VarDeclaration, and the previous
stack address of that variable, so that we can restore it
when we leave the stack frame.
Note that when a function is forward referenced, the interpreter must
run semantic3, and that may start CTFE again with a NULL istate. Thus
the stack might not be empty when CTFE begins.
Ctfe Stack addresses are just 0-based integers, but we save
them as 'void *' because ArrayBase can only do pointers.
*/
@@ -143,7 +146,11 @@ public:
}
void saveGlobalConstant(VarDeclaration *v, Expression *e)
{
assert(v->isDataseg() && !v->isCTFE());
#if DMDV2
assert( v->init && (v->isConst() || v->isImmutable()) && !v->isCTFE());
#else
assert( v->init && v->isConst() && !v->isCTFE());
#endif
v->ctfeAdrOnStack = globalValues.dim;
globalValues.push(e);
}
@@ -208,7 +215,7 @@ VarDeclaration *findParentVar(Expression *e, Expression *thisval);
bool needToCopyLiteral(Expression *expr);
Expression *copyLiteral(Expression *e);
Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2);
Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2);
Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
FuncDeclaration *fd, Expressions *arguments, Expression *pthis);
Expression *scrubReturnValue(Loc loc, Expression *e);
@@ -243,6 +250,16 @@ struct ClassReferenceExp : Expression
{
return value->sd->isClassDeclaration();
}
VarDeclaration *getFieldAt(int index)
{
ClassDeclaration *cd = originalClass();
size_t fieldsSoFar = 0;
while (index - fieldsSoFar >= cd->fields.dim)
{ fieldsSoFar += cd->fields.dim;
cd = cd->baseClass;
}
return cd->fields.tdata()[index - fieldsSoFar];
}
// Return index of the field, or -1 if not found
int getFieldIndex(Type *fieldtype, size_t fieldoffset)
{
@@ -283,6 +300,28 @@ struct ClassReferenceExp : Expression
}
};
struct VoidInitExp : Expression
{
VarDeclaration *var;
VoidInitExp(VarDeclaration *var, Type *type)
: Expression(var->loc, TOKvoid, sizeof(VoidInitExp))
{
this->var = var;
this->type = var->type;
}
char *toChars()
{
return (char *)"void";
}
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue)
{
error("CTFE internal error: trying to read uninitialized variable");
assert(0);
return EXP_CANT_INTERPRET;
}
};
// Return index of the field, or -1 if not found
// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v)
@@ -456,7 +495,8 @@ void showCtfeExpr(Expression *e, int level = 0)
* arguments function arguments
* thisarg 'this', if a needThis() function, NULL if not.
*
* Return result expression if successful, EXP_CANT_INTERPRET if not.
* Return result expression if successful, EXP_CANT_INTERPRET if not,
* or EXP_VOID_INTERPRET if function returned void.
*/
Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg)
@@ -475,7 +515,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
*/
int olderrors = global.errors;
int oldgag = global.gag;
TemplateInstance *spec = isSpeculativeFunction(this);
TemplateInstance *spec = isSpeculative();
if (global.gag && !spec)
global.gag = 0;
semantic3(scope);
@@ -576,6 +616,15 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
--evaluatingArgs;
if (earg == EXP_CANT_INTERPRET)
return earg;
/* Struct literals are passed by value, but we don't need to
* copy them if they are passed as const
*/
if (earg->op == TOKstructliteral
#if DMDV2
&& !(arg->storageClass & (STCconst | STCimmutable))
#endif
)
earg = copyLiteral(earg);
}
if (earg->op == TOKthrownexception)
{
@@ -675,6 +724,11 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
// If fell off the end of a void function, return void
if (!e && type->toBasetype()->nextOf()->ty == Tvoid)
return EXP_VOID_INTERPRET;
// If result is void, return void
if (e == EXP_VOID_INTERPRET)
return e;
// If it generated an exception, return it
if (exceptionOrCantInterpret(e))
{
@@ -683,6 +737,9 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
((ThrownExceptionExp *)e)->generateUncaughtError();
return EXP_CANT_INTERPRET;
}
// If we're about to leave CTFE, make sure we don't crash the
// compiler by returning a CTFE-internal expression.
if (!istate && !evaluatingArgs)
{
e = scrubReturnValue(loc, e);
@@ -896,13 +953,16 @@ uinteger_t resolveArrayLength(Expression *e)
}
// As Equal, but resolves slices before comparing
Expression *ctfeEqual(enum TOK op, Type *type, Expression *e1, Expression *e2)
Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2)
{
if (e1->op == TOKslice)
e1 = resolveSlice(e1);
if (e2->op == TOKslice)
e2 = resolveSlice(e2);
return Equal(op, type, e1, e2);
Expression *e = Equal(op, type, e1, e2);
if (e == EXP_CANT_INTERPRET)
error(loc, "cannot evaluate %s==%s at compile time", e1->toChars(), e2->toChars());
return e;
}
Expression *ctfeCat(Type *type, Expression *e1, Expression *e2)
@@ -973,7 +1033,7 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2)
return Cat(type, e1, e2);
}
void scrubArray(Loc loc, Expressions *elems);
bool scrubArray(Loc loc, Expressions *elems, bool structlit = false);
/* All results destined for use outside of CTFE need to have their CTFE-specific
* features removed.
@@ -986,6 +1046,11 @@ Expression *scrubReturnValue(Loc loc, Expression *e)
error(loc, "%s class literals cannot be returned from CTFE", ((ClassReferenceExp*)e)->originalClass()->toChars());
return EXP_CANT_INTERPRET;
}
if (e->op == TOKvoid)
{
error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
e = new ErrorExp();
}
if (e->op == TOKslice)
{
e = resolveSlice(e);
@@ -994,7 +1059,8 @@ Expression *scrubReturnValue(Loc loc, Expression *e)
{
StructLiteralExp *se = (StructLiteralExp *)e;
se->ownedByCtfe = false;
scrubArray(loc, se->elements);
if (!scrubArray(loc, se->elements, true))
return EXP_CANT_INTERPRET;
}
if (e->op == TOKstring)
{
@@ -1003,29 +1069,38 @@ Expression *scrubReturnValue(Loc loc, Expression *e)
if (e->op == TOKarrayliteral)
{
((ArrayLiteralExp *)e)->ownedByCtfe = false;
scrubArray(loc, ((ArrayLiteralExp *)e)->elements);
if (!scrubArray(loc, ((ArrayLiteralExp *)e)->elements))
return EXP_CANT_INTERPRET;
}
if (e->op == TOKassocarrayliteral)
{
AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
aae->ownedByCtfe = false;
scrubArray(loc, aae->keys);
scrubArray(loc, aae->values);
if (!scrubArray(loc, aae->keys))
return EXP_CANT_INTERPRET;
if (!scrubArray(loc, aae->values))
return EXP_CANT_INTERPRET;
}
return e;
}
// Scrub all members of an array
void scrubArray(Loc loc, Expressions *elems)
// Scrub all members of an array. Return false if error
bool scrubArray(Loc loc, Expressions *elems, bool structlit)
{
for (size_t i = 0; i < elems->dim; i++)
{
Expression *m = elems->tdata()[i];
if (!m)
continue;
m = scrubReturnValue(loc, m);
if (m && m->op == TOKvoid && structlit)
m = NULL;
if (m)
m = scrubReturnValue(loc, m);
if (m == EXP_CANT_INTERPRET)
return false;
elems->tdata()[i] = m;
}
return true;
}
@@ -1360,7 +1435,7 @@ Expression *SwitchStatement::interpret(InterState *istate)
Expression * caseExp = cs->exp->interpret(istate);
if (exceptionOrCantInterpret(caseExp))
return caseExp;
e = ctfeEqual(TOKequal, Type::tint32, econdition, caseExp);
e = ctfeEqual(caseExp->loc, TOKequal, Type::tint32, econdition, caseExp);
if (exceptionOrCantInterpret(e))
return e;
if (e->isBool(TRUE))
@@ -1475,25 +1550,25 @@ Expression *TryCatchStatement::interpret(InterState *istate)
ThrownExceptionExp *ex = (ThrownExceptionExp *)e;
Type *extype = ex->thrown->originalClass()->type;
// Search for an appropriate catch clause.
for (size_t i = 0; i < catches->dim; i++)
{
for (size_t i = 0; i < catches->dim; i++)
{
#if DMDV1
Catch *ca = (Catch *)catches->data[i];
Catch *ca = (Catch *)catches->data[i];
#else
Catch *ca = catches->tdata()[i];
Catch *ca = catches->tdata()[i];
#endif
Type *catype = ca->type;
Type *catype = ca->type;
if (catype->equals(extype) || catype->isBaseOf(extype, NULL))
{ // Execute the handler
if (catype->equals(extype) || catype->isBaseOf(extype, NULL))
{ // Execute the handler
if (ca->var)
{
ctfeStack.push(ca->var);
ca->var->setValue(ex->thrown);
}
return ca->handler->interpret(istate);
}
return ca->handler ? ca->handler->interpret(istate) : NULL;
}
}
return e;
}
@@ -1734,6 +1809,8 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal)
}
Type *pointee = ((TypePointer *)type)->next;
Expression *val = getVarExp(loc, istate, var, goal);
if (val == EXP_CANT_INTERPRET)
return val;
if (val->type->ty == Tarray || val->type->ty == Tsarray)
{
// Check for unsupported type painting operations
@@ -1907,10 +1984,7 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception)
{
e = copyLiteral(e);
if (v->isDataseg())
ctfeStack.saveGlobalConstant(v, e);
else
v->setValueWithoutChecking(e);
ctfeStack.saveGlobalConstant(v, e);
}
}
else if (v->isCTFE() && !v->hasValue())
@@ -1919,11 +1993,16 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
{
if (v->init->isVoidInitializer())
{
error(loc, "variable %s is used before initialization", v->toChars());
return EXP_CANT_INTERPRET;
// var should have been initialized when it was created
error(loc, "CTFE internal error - trying to access uninitialized var");
assert(0);
e = EXP_CANT_INTERPRET;
}
else
{
e = v->init->toExpression();
e = e->interpret(istate);
}
e = v->init->toExpression();
e = e->interpret(istate);
}
else
e = v->type->defaultInitLiteral(loc);
@@ -1939,7 +2018,11 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
e = EXP_CANT_INTERPRET;
}
else if (!e)
error(loc, "variable %s is used before initialization", v->toChars());
{
assert(0);
assert(v->init && v->init->isVoidInitializer());
e = v->type->voidInitLiteral(v);
}
else if (exceptionOrCantInterpret(e))
return e;
else if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex)
@@ -1958,6 +2041,13 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
|| e->op == TOKassocarrayliteral || e->op == TOKslice
|| e->type->toBasetype()->ty == Tpointer)
return e; // it's already an Lvalue
else if (e->op == TOKvoid)
{
VoidInitExp *ve = (VoidInitExp *)e;
error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars());
errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars());
e = EXP_CANT_INTERPRET;
}
else
e = e->interpret(istate, goal);
}
@@ -1971,10 +2061,12 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
if (s->dsym->toInitializer() == s->sym)
{
#endif
e = s->dsym->type->defaultInitLiteral();
e = s->dsym->type->defaultInitLiteral(loc);
e = e->semantic(NULL);
if (e->op == TOKerror)
e = EXP_CANT_INTERPRET;
else // Convert NULL to VoidExp
e = e->interpret(istate, goal);
#if !IN_LLVM
}
else
@@ -2045,7 +2137,12 @@ Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal)
if (ie)
e = ie->exp->interpret(istate);
else if (v->init->isVoidInitializer())
e = NULL;
{
e = v->type->voidInitLiteral(v);
// There is no AssignExp for void initializers,
// so set it here.
v->setValue(e);
}
else
{
error("Declaration %s is not yet implemented in CTFE", toChars());
@@ -2274,7 +2371,7 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal)
ekey = resolveSlice(ekey);
for (size_t j = i; j < keysx->dim; j++)
{ Expression *ekey2 = keysx->tdata()[j];
Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, ekey2);
Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, ekey2);
if (ex == EXP_CANT_INTERPRET)
goto Lerr;
if (ex->isBool(TRUE)) // if a match
@@ -2448,10 +2545,10 @@ Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *is
if (elemType->ty == Tchar || elemType->ty == Twchar
|| elemType->ty == Tdchar)
return createBlockDuplicatedStringLiteral(loc, newtype,
(unsigned)(elemType->defaultInitLiteral()->toInteger()),
(unsigned)(elemType->defaultInitLiteral(loc)->toInteger()),
len, elemType->size());
return createBlockDuplicatedArrayLiteral(loc, newtype,
elemType->defaultInitLiteral(),
elemType->defaultInitLiteral(loc),
len);
}
@@ -2465,7 +2562,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal)
if (newtype->toBasetype()->ty == Tstruct)
{
Expression *se = newtype->defaultInitLiteral();
Expression *se = newtype->defaultInitLiteral(loc);
#if DMDV2
if (member)
{
@@ -2502,7 +2599,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal)
Dsymbol *s = c->fields.tdata()[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v);
Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral();
Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(loc);
if (exceptionOrCantInterpret(m))
return m;
elems->tdata()[fieldsSoFar+i] = copyLiteral(m);
@@ -2672,7 +2769,7 @@ Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type,
}
if (indx < 0 || indx > len)
{
error(loc, "cannot assign pointer to index %jd inside memory block [0..%jd]", indx, len);
error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", indx, len);
return EXP_CANT_INTERPRET;
}
@@ -2974,7 +3071,7 @@ Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, Expressi
for (size_t j = valuesx->dim; j; )
{ j--;
Expression *ekey = aae->keys->tdata()[j];
Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index);
Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, index);
if (exceptionOrCantInterpret(ex))
return ex;
if (ex->isBool(TRUE))
@@ -3144,7 +3241,7 @@ Expression *copyLiteral(Expression *e)
assert(v);
// If it is a void assignment, use the default initializer
if (!m)
m = v->type->defaultInitLiteral(e->loc);
m = v->type->voidInitLiteral(v);
if (m->op == TOKslice)
m = resolveSlice(m);
if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray)
@@ -3171,7 +3268,8 @@ Expression *copyLiteral(Expression *e)
|| e->op == TOKsymoff || e->op == TOKnull
|| e->op == TOKvar
|| e->op == TOKint64 || e->op == TOKfloat64
|| e->op == TOKchar || e->op == TOKcomplex80)
|| e->op == TOKchar || e->op == TOKcomplex80
|| e->op == TOKvoid)
{ // Simple value types
Expression *r = e->syntaxCopy();
r->type = e->type;
@@ -3341,7 +3439,7 @@ void assignInPlace(Expression *dest, Expression *src)
assert(o->op == e->op);
assignInPlace(o, e);
}
else if (e->type->ty == Tsarray && o->type->ty == Tsarray)
else if (e->type->ty == Tsarray && o->type->ty == Tsarray && e->op != TOKvoid)
{
assignInPlace(o, e);
}
@@ -3636,7 +3734,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
Type *elemType= NULL;
elemType = ((TypeArray *)t)->next;
assert(elemType);
Expression *defaultElem = elemType->defaultInitLiteral();
Expression *defaultElem = elemType->defaultInitLiteral(loc);
Expressions *elements = new Expressions();
elements->setDim(newlen);
@@ -3744,7 +3842,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
// only modifying part of the variable. So we need to make sure
// that the parent variable exists.
if (e1->op != TOKvar && ultimateVar && !ultimateVar->getValue())
ultimateVar->setValue(copyLiteral(ultimateVar->type->defaultInitLiteral()));
ultimateVar->setValue(copyLiteral(ultimateVar->type->defaultInitLiteral(loc)));
// ---------------------------------------
// Deal with reference assignment
@@ -3822,7 +3920,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
indx = resolveSlice(indx);
// Look up this index in it up in the existing AA, to get the next level of AA.
AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(existingAA, indx);
AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(loc, existingAA, indx);
if (exceptionOrCantInterpret(newAA))
return newAA;
if (!newAA)
@@ -3968,14 +4066,29 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
? (StructLiteralExp *)exx
: ((ClassReferenceExp *)exx)->value;
int fieldi = exx->op == TOKstructliteral
? se->getFieldIndex(member->type, member->offset)
: ((ClassReferenceExp *)exx)->getFieldIndex(member->type, member->offset);
? findFieldIndexByName(se->sd, member)
: ((ClassReferenceExp *)exx)->findFieldIndexByName(member);
if (fieldi == -1)
{
error("CTFE internal error: cannot find field %s in %s", member->toChars(), exx->toChars());
return EXP_CANT_INTERPRET;
}
assert(fieldi>=0 && fieldi < se->elements->dim);
assert(fieldi >= 0 && fieldi < se->elements->dim);
// If it's a union, set all other members of this union to void
if (exx->op == TOKstructliteral)
{
assert(se->sd);
int unionStart = se->sd->firstFieldInUnion(fieldi);
int unionSize = se->sd->numFieldsInUnion(fieldi);
for(int i = unionStart; i < unionStart + unionSize; ++i)
{ if (i == fieldi)
continue;
Expression **el = &se->elements->tdata()[i];
if ((*el)->op != TOKvoid)
*el = (*el)->type->voidInitLiteral(member);
}
}
if (newval->op == TOKstructliteral)
assignInPlace(se->elements->tdata()[fieldi], newval);
else
@@ -4050,6 +4163,21 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
}
aggregate = getAggregateFromPointer(aggregate, &ofs);
indexToModify += ofs;
if (aggregate->op != TOKslice && aggregate->op != TOKstring &&
aggregate->op != TOKarrayliteral && aggregate->op != TOKassocarrayliteral)
{
if (indexToModify != 0)
{
error("pointer index [%lld] lies outside memory block [0..1]", indexToModify);
return EXP_CANT_INTERPRET;
}
// It is equivalent to *aggregate = newval.
// Aggregate could be varexp, a dotvar, ...
// TODO: we could support this
error("indexed assignment of non-array pointers is not yet supported at compile time; use *%s = %s instead",
ie->e1->toChars(), e2->toChars());
return EXP_CANT_INTERPRET;
}
destarraylen = resolveArrayLength(aggregate);
}
if (indexToModify >= destarraylen)
@@ -4075,7 +4203,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral)
{
IndexExp *ix = (IndexExp *)aggregate;
aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2);
aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2);
if (!aggregate)
{
error("key %s not found in associative array %s",
@@ -4177,6 +4305,8 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
if (isPointer(oldval->type))
{ // Slicing a pointer
oldval = oldval->interpret(istate, ctfeNeedLvalue);
if (exceptionOrCantInterpret(oldval))
return oldval;
dinteger_t ofs;
oldval = getAggregateFromPointer(oldval, &ofs);
assignmentToSlicedPointer = true;
@@ -4186,7 +4316,13 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
if (oldval->op != TOKarrayliteral && oldval->op != TOKstring
&& oldval->op != TOKslice && oldval->op != TOKnull)
{
error("CTFE ICE: cannot resolve array length");
if (assignmentToSlicedPointer)
{
error("pointer %s cannot be sliced at compile time (it does not point to an array)",
sexp->e1->toChars());
}
else
error("CTFE ICE: cannot resolve array length");
return EXP_CANT_INTERPRET;
}
uinteger_t dollar = resolveArrayLength(oldval);
@@ -4249,7 +4385,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral)
{
IndexExp *ix = (IndexExp *)aggregate;
aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2);
aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2);
if (!aggregate)
{
error("key %s not found in associative array %s",
@@ -4273,7 +4409,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
firstIndex = lowerbound + sexpold->lwr->toInteger();
if (hi > sexpold->upr->toInteger())
{
error("slice [%d..%d] exceeds array bounds [0..%jd]",
error("slice [%d..%d] exceeds array bounds [0..%lld]",
lowerbound, upperbound,
sexpold->upr->toInteger() - sexpold->lwr->toInteger());
return EXP_CANT_INTERPRET;
@@ -4285,11 +4421,16 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue);
dinteger_t ofs;
aggregate = getAggregateFromPointer(aggregate, &ofs);
if (aggregate->op == TOKnull)
{
error("cannot slice null pointer %s", sexp->e1->toChars());
return EXP_CANT_INTERPRET;
}
dinteger_t hi = upperbound + ofs;
firstIndex = lowerbound + ofs;
if (firstIndex < 0 || hi > dim)
{
error("slice [%d..%jd] exceeds memory block bounds [0..%jd]",
error("slice [lld..%lld] exceeds memory block bounds [0..%lld]",
firstIndex, hi, dim);
return EXP_CANT_INTERPRET;
}
@@ -4430,9 +4571,6 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
else
{
error("%s cannot be evaluated at compile time", toChars());
#ifdef DEBUG
dump(0);
#endif
}
return returnValue;
}
@@ -4812,6 +4950,10 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal)
if (!global.gag)
showCtfeBackTrace(istate, this, fd);
}
else if (eresult == EXP_VOID_INTERPRET)
;
else
eresult->loc = loc;
return eresult;
}
@@ -4830,7 +4972,6 @@ Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal)
InterState istateComma;
if (!istate && firstComma->e1->op == TOKdeclaration)
{
assert(ctfeStack.stackPointer() == 0);
ctfeStack.startFrame();
istate = &istateComma;
}
@@ -4848,7 +4989,7 @@ Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal)
ctfeStack.push(v);
if (!v->init && !v->getValue())
{
v->setValue(copyLiteral(v->type->defaultInitLiteral()));
v->setValue(copyLiteral(v->type->defaultInitLiteral(loc)));
}
if (!v->getValue()) {
Expression *newval = v->init->toExpression();
@@ -4944,7 +5085,7 @@ Expression *ArrayLengthExp::interpret(InterState *istate, CtfeGoal goal)
* Return ae[e2] if present, or NULL if not found.
* Return EXP_CANT_INTERPRET on error.
*/
Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2)
Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2)
{
/* Search the keys backwards, in case there are duplicate keys
*/
@@ -4952,13 +5093,9 @@ Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2)
{
i--;
Expression *ekey = ae->keys->tdata()[i];
Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, e2);
Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, e2);
if (ex == EXP_CANT_INTERPRET)
{
error("cannot evaluate %s==%s at compile time",
ekey->toChars(), e2->toChars());
return ex;
}
if (ex->isBool(TRUE))
{
return ae->values->tdata()[i];
@@ -5013,23 +5150,37 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal)
if (exceptionOrCantInterpret(e2))
return e2;
dinteger_t indx = e2->toInteger();
dinteger_t ofs;
Expression *agg = getAggregateFromPointer(e1, &ofs);
if (agg->op == TOKnull)
{
error("cannot index null pointer %s", this->e1->toChars());
return EXP_CANT_INTERPRET;
}
assert(agg->op == TOKarrayliteral || agg->op == TOKstring);
dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger();
Type *pointee = ((TypePointer *)agg->type)->next;
if ((indx + ofs) < 0 || (indx+ofs) > len)
if ( agg->op == TOKarrayliteral || agg->op == TOKstring)
{
error("pointer index [%jd] exceeds allocated memory block [0..%jd]",
indx+ofs, len);
return EXP_CANT_INTERPRET;
dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger();
Type *pointee = ((TypePointer *)agg->type)->next;
if ((indx + ofs) < 0 || (indx+ofs) > len)
{
error("pointer index [%lld] exceeds allocated memory block [0..%lld]",
indx+ofs, len);
return EXP_CANT_INTERPRET;
}
return ctfeIndex(loc, type, agg, indx+ofs);
}
else
{ // Pointer to a non-array variable
if ((indx + ofs) != 0)
{
error("pointer index [%lld] lies outside memory block [0..1]",
indx+ofs);
return EXP_CANT_INTERPRET;
}
return agg->interpret(istate);
}
return ctfeIndex(loc, type, agg, indx+ofs);
}
e1 = this->e1;
if (!(e1->op == TOKarrayliteral && ((ArrayLiteralExp *)e1)->ownedByCtfe))
@@ -5070,7 +5221,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal)
if (indx > iup - ilo)
{
error("index %ju exceeds array length %ju", indx, iup - ilo);
error("index %llu exceeds array length %llu", indx, iup - ilo);
return EXP_CANT_INTERPRET;
}
indx += ilo;
@@ -5091,7 +5242,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal)
{
if (e2->op == TOKslice)
e2 = resolveSlice(e2);
e = findKeyInAA((AssocArrayLiteralExp *)e1, e2);
e = findKeyInAA(loc, (AssocArrayLiteralExp *)e1, e2);
if (!e)
{
error("key %s not found in associative array %s",
@@ -5112,6 +5263,12 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal)
return e;
if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar))
e = e->interpret(istate);
if (goal == ctfeNeedRvalue && e->op == TOKvoid)
{
error("%s is used before initialized", toChars());
errorSupplemental(e->loc, "originally uninitialized here");
return EXP_CANT_INTERPRET;
}
e = paintTypeOntoLiteral(type, e);
return e;
}
@@ -5166,12 +5323,18 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal)
error("cannot slice null pointer %s", this->e1->toChars());
return EXP_CANT_INTERPRET;
}
if (agg->op != TOKarrayliteral && agg->op != TOKstring)
{
error("pointer %s cannot be sliced at compile time (it does not point to an array)",
this->e1->toChars());
return EXP_CANT_INTERPRET;
}
assert(agg->op == TOKarrayliteral || agg->op == TOKstring);
dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger();
Type *pointee = ((TypePointer *)agg->type)->next;
if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr)
{
error("pointer slice [%jd..%jd] exceeds allocated memory block [0..%jd]",
error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]",
ilwr+ofs, iupr+ofs, len);
return EXP_CANT_INTERPRET;
}
@@ -5235,7 +5398,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal)
{
if (ilwr== 0 && iupr == 0)
return e1;
e1->error("slice [%ju..%ju] is out of bounds", ilwr, iupr);
e1->error("slice [%llu..%llu] is out of bounds", ilwr, iupr);
return EXP_CANT_INTERPRET;
}
if (e1->op == TOKslice)
@@ -5247,7 +5410,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal)
uinteger_t up1 = se->upr->toInteger();
if (ilwr > iupr || iupr > up1 - lo1)
{
error("slice[%ju..%ju] exceeds array bounds[%ju..%ju]",
error("slice[%llu..%llu] exceeds array bounds[%llu..%llu]",
ilwr, iupr, lo1, up1);
return EXP_CANT_INTERPRET;
}
@@ -5264,7 +5427,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal)
{
if (iupr < ilwr || ilwr < 0 || iupr > dollar)
{
error("slice [%jd..%jd] exceeds array bounds [0..%jd]",
error("slice [%lld..%lld] exceeds array bounds [0..%lld]",
ilwr, iupr, dollar);
return EXP_CANT_INTERPRET;
}
@@ -5295,7 +5458,7 @@ Expression *InExp::interpret(InterState *istate, CtfeGoal goal)
}
if (e1->op == TOKslice)
e1 = resolveSlice(e1);
e = findKeyInAA((AssocArrayLiteralExp *)e2, e1);
e = findKeyInAA(loc, (AssocArrayLiteralExp *)e2, e1);
if (exceptionOrCantInterpret(e))
return e;
if (!e)
@@ -5354,8 +5517,12 @@ bool isAssocArray(Type *t)
if (t->ty != Tstruct)
return false;
StructDeclaration *sym = ((TypeStruct *)t)->sym;
if (sym->ident == Id::AssociativeArray)
if (sym->ident == Id::AssociativeArray && sym->parent &&
sym->parent->parent &&
sym->parent->parent->ident == Id::object)
{
return true;
}
#endif
return false;
}
@@ -5510,9 +5677,15 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal)
e->type = type;
return e;
}
error("pointer cast from %s to %s is not supported at compile time",
// Check if we have a null pointer (eg, inside a struct)
e1 = e1->interpret(istate);
if (e1->op != TOKnull)
{
error("pointer cast from %s to %s is not supported at compile time",
e1->type->toChars(), to->toChars());
return EXP_CANT_INTERPRET;
return EXP_CANT_INTERPRET;
}
}
if (to->ty == Tarray && e1->op == TOKslice)
{
@@ -5660,7 +5833,7 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal)
assert(indx >=0 && indx <= len); // invalid pointer
if (indx == len)
{
error("dereference of pointer %s one past end of memory block limits [0..%jd]",
error("dereference of pointer %s one past end of memory block limits [0..%lld]",
toChars(), len);
return EXP_CANT_INTERPRET;
}
@@ -5705,7 +5878,7 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal)
}
else if (e->op == TOKaddress)
e = ((AddrExp*)e)->e1; // *(&x) ==> x
if (e->op == TOKnull)
else if (e->op == TOKnull)
{
error("dereference of null pointer '%s'", e1->toChars());
return EXP_CANT_INTERPRET;
@@ -5794,6 +5967,13 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal)
if (e->op == TOKstructliteral || e->op == TOKarrayliteral ||
e->op == TOKassocarrayliteral || e->op == TOKstring)
return e;
if (e->op == TOKvoid)
{
VoidInitExp *ve = (VoidInitExp *)e;
error("cannot read uninitialized variable %s in ctfe", toChars());
ve->var->error("was uninitialized and used before set");
return EXP_CANT_INTERPRET;
}
if ( isPointer(type) )
{
return paintTypeOntoLiteral(type, e);
@@ -5838,7 +6018,7 @@ Expression *RemoveExp::interpret(InterState *istate, CtfeGoal goal)
size_t removed = 0;
for (size_t j = 0; j < valuesx->dim; ++j)
{ Expression *ekey = keysx->tdata()[j];
Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index);
Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, index);
if (exceptionOrCantInterpret(ex))
return ex;
if (ex->isBool(TRUE))
@@ -6017,7 +6197,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del
else if (str->op == TOKarrayliteral)
ale = (ArrayLiteralExp *)str;
else
{ error("CTFE internal error: cannot foreach %s", str->toChars());
{ str->error("CTFE internal error: cannot foreach %s", str->toChars());
return EXP_CANT_INTERPRET;
}
Expressions args;
@@ -6472,6 +6652,10 @@ bool isCtfeValueValid(Expression *newval)
assert(((ArrayLiteralExp *)se->e1)->ownedByCtfe);
return true;
}
if (newval->op == TOKvoid)
{
return true;
}
newval->error("CTFE internal error: illegal value %s\n", newval->toChars());
return false;
}
@@ -6504,3 +6688,29 @@ void VarDeclaration::setValue(Expression *newval)
assert(isCtfeValueValid(newval));
ctfeStack.setValue(this, newval);
}
Expression *Type::voidInitLiteral(VarDeclaration *var)
{
return new VoidInitExp(var, this);
}
Expression *TypeSArray::voidInitLiteral(VarDeclaration *var)
{
return createBlockDuplicatedArrayLiteral(var->loc, this, next->voidInitLiteral(var), dim->toInteger());
}
Expression *TypeStruct::voidInitLiteral(VarDeclaration *var)
{
Expressions *exps = new Expressions();
exps->setDim(sym->fields.dim);
for (size_t i = 0; i < sym->fields.dim; i++)
{
//(*exps)[i] = new VoidInitExp(var, sym->fields[i]->type);
(*exps)[i] = sym->fields[i]->type->voidInitLiteral(var);
}
StructLiteralExp *se = new StructLiteralExp(var->loc, sym, exps);
se->type = this;
se->ownedByCtfe = true;
return se;
}