Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 6169 - [CTFE] pure functions cannot compute constants using functions not marked as pure #652

Merged
merged 1 commit into from May 4, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/attrib.c
Expand Up @@ -971,7 +971,7 @@ void PragmaDeclaration::semantic(Scope *sc)
{
Expression *e = (*args)[i];

e = e->semantic(sc);
e = e->ctfeSemantic(sc);
e = resolveProperties(sc, e);
if (e->op != TOKerror && e->op != TOKtype)
e = e->ctfeInterpret();
Expand Down Expand Up @@ -999,7 +999,7 @@ void PragmaDeclaration::semantic(Scope *sc)
{
Expression *e = (*args)[0];

e = e->semantic(sc);
e = e->ctfeSemantic(sc);
e = resolveProperties(sc, e);
e = e->ctfeInterpret();
(*args)[0] = e;
Expand Down Expand Up @@ -1027,7 +1027,7 @@ void PragmaDeclaration::semantic(Scope *sc)
else
{
Expression *e = (*args)[0];
e = e->semantic(sc);
e = e->ctfeSemantic(sc);
e = resolveProperties(sc, e);
e = e->ctfeInterpret();
(*args)[0] = e;
Expand All @@ -1050,7 +1050,7 @@ void PragmaDeclaration::semantic(Scope *sc)
for (size_t i = 0; i < args->dim; i++)
{
Expression *e = (*args)[i];
e = e->semantic(sc);
e = e->ctfeSemantic(sc);
e = resolveProperties(sc, e);
e = e->ctfeInterpret();
if (i == 0)
Expand Down Expand Up @@ -1428,7 +1428,7 @@ int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
void CompileDeclaration::compileIt(Scope *sc)
{
//printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars());
exp = exp->semantic(sc);
exp = exp->ctfeSemantic(sc);
exp = resolveProperties(sc, exp);
exp = exp->ctfeInterpret();
StringExp *se = exp->toString();
Expand Down
2 changes: 1 addition & 1 deletion src/cond.c
Expand Up @@ -259,7 +259,7 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
sc = sc->push(sc->scopesym);
sc->sd = s; // s gets any addMember()
sc->flags |= SCOPEstaticif;
Expression *e = exp->semantic(sc);
Expression *e = exp->ctfeSemantic(sc);
e = resolveProperties(sc, e);
sc->pop();
if (!e->type->checkBoolean())
Expand Down
12 changes: 11 additions & 1 deletion src/declaration.c
Expand Up @@ -851,6 +851,11 @@ void VarDeclaration::semantic(Scope *sc)
if (!type)
{ inuse++;

// Infering the type requires running semantic,
// so mark the scope as ctfe if required
if (storage_class & (STCmanifest | STCstatic))
sc->needctfe++;

//printf("inferring type for %s with init %s\n", toChars(), init->toChars());
ArrayInitializer *ai = init->isArrayInitializer();
if (ai)
Expand All @@ -872,6 +877,8 @@ void VarDeclaration::semantic(Scope *sc)
else
type = init->inferType(sc);

if (storage_class & (STCmanifest | STCstatic))
sc->needctfe--;
// type = type->semantic(loc, sc);

inuse--;
Expand Down Expand Up @@ -1585,7 +1592,10 @@ void VarDeclaration::semantic(Scope *sc)
{
Expression *exp;
exp = ei->exp->syntaxCopy();
exp = exp->semantic(sc);
if (isDataseg() || (storage_class & STCmanifest))
exp = exp->ctfeSemantic(sc);
else
exp = exp->semantic(sc);
exp = resolveProperties(sc, exp);
Type *tb = type->toBasetype();
Type *ti = exp->type->toBasetype();
Expand Down
14 changes: 7 additions & 7 deletions src/enum.c
Expand Up @@ -252,7 +252,7 @@ void EnumDeclaration::semantic(Scope *sc)
if (e)
{
assert(e->dyncast() == DYNCAST_EXPRESSION);
e = e->semantic(sce);
e = e->ctfeSemantic(sce);
e = e->ctfeInterpret();
if (memtype)
{
Expand Down Expand Up @@ -299,30 +299,30 @@ void EnumDeclaration::semantic(Scope *sc)
if (!emax)
{
emax = t->getProperty(0, Id::max, 0);
emax = emax->semantic(sce);
emax = emax->ctfeSemantic(sce);
emax = emax->ctfeInterpret();
}

// Set value to (elast + 1).
// But first check that (elast != t.max)
assert(elast);
e = new EqualExp(TOKequal, em->loc, elast, emax);
e = e->semantic(sce);
e = e->ctfeSemantic(sce);
e = e->ctfeInterpret();
if (e->toInteger())
error("overflow of enum value %s", elast->toChars());

// Now set e to (elast + 1)
e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32));
e = e->semantic(sce);
e = e->ctfeSemantic(sce);
e = e->castTo(sce, elast->type);
e = e->ctfeInterpret();

if (t->isfloating())
{
// Check that e != elast (not always true for floats)
Expression *etest = new EqualExp(TOKequal, em->loc, e, elast);
etest = etest->semantic(sce);
etest = etest->ctfeSemantic(sce);
etest = etest->ctfeInterpret();
if (etest->toInteger())
error("enum member %s has inexact value, due to loss of precision", em->toChars());
Expand Down Expand Up @@ -361,13 +361,13 @@ void EnumDeclaration::semantic(Scope *sc)

// Compute if(e < minval)
ec = new CmpExp(TOKlt, em->loc, e, minval);
ec = ec->semantic(sce);
ec = ec->ctfeSemantic(sce);
ec = ec->ctfeInterpret();
if (ec->toInteger())
minval = e;

ec = new CmpExp(TOKgt, em->loc, e, maxval);
ec = ec->semantic(sce);
ec = ec->ctfeSemantic(sce);
ec = ec->ctfeInterpret();
if (ec->toInteger())
maxval = e;
Expand Down
71 changes: 58 additions & 13 deletions src/expression.c
Expand Up @@ -1537,6 +1537,29 @@ Expression *Expression::trySemantic(Scope *sc)
return e;
}

/**********************************
* Shortcut to run semantic with purity and
* safety checking disabled for the immediate
* expressions
*/

Expression *Expression::ctfeSemantic(Scope *sc)
{
if (sc)
{
assert(sc->needctfe >= 0);
sc->needctfe++;
Expression *e = semantic(sc);
sc->needctfe--;
assert(sc->needctfe >= 0);
return e;
}
else
{
return semantic(sc);
}
}

void Expression::print()
{
fprintf(stdmsg, "%s\n", toChars());
Expand Down Expand Up @@ -1876,7 +1899,8 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f)
// If the caller has a pure parent, then either the called func must be pure,
// OR, they must have the same pure parent.
if (/*outerfunc->isPure() &&*/ // comment out because we deduce purity now
!f->isPure() && calledparent != outerfunc)
!f->isPure() && calledparent != outerfunc &&
!sc->needctfe)
{
if (outerfunc->setImpure())
error("pure function '%s' cannot call impure function '%s'",
Expand Down Expand Up @@ -1977,6 +2001,7 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis)
void Expression::checkSafety(Scope *sc, FuncDeclaration *f)
{
if (sc->func && !sc->intypeof &&
!(sc->needctfe) &&
!f->isSafe() && !f->isTrusted())
{
if (sc->func->setUnsafe())
Expand Down Expand Up @@ -4968,7 +4993,10 @@ Expression *NewAnonClassExp::semantic(Scope *sc)
#endif

Expression *d = new DeclarationExp(loc, cd);
int needctfe = sc->needctfe;
sc->needctfe = 0;
d = d->semantic(sc);
sc->needctfe = needctfe;

Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments);

Expand Down Expand Up @@ -5392,6 +5420,11 @@ Expression *FuncExp::semantic(Scope *sc)
printf("FuncExp::semantic(%s)\n", toChars());
if (fd->treq) printf(" treq = %s\n", fd->treq->toChars());
#endif
Expression *e = this;

int needctfe = sc->needctfe;
sc->needctfe = 0;

if (!type || type == Type::tvoid)
{
/* fd->treq might be incomplete type,
Expand Down Expand Up @@ -5421,10 +5454,9 @@ Expression *FuncExp::semantic(Scope *sc)
td->semantic(sc);
type = Type::tvoid; // temporary type

if (!fd->treq) // defer type determination
return this;

return inferType(fd->treq);
if (fd->treq) // defer type determination
e = inferType(fd->treq);
goto Ldone;
}

unsigned olderrors = global.errors;
Expand Down Expand Up @@ -5479,7 +5511,9 @@ Expression *FuncExp::semantic(Scope *sc)
}
fd->tookAddressOf++;
}
return this;
Ldone:
sc->needctfe = needctfe;
return e;
}

// used from CallExp::semantic()
Expand Down Expand Up @@ -6563,7 +6597,7 @@ Expression *CompileExp::semantic(Scope *sc)
#if LOGSEMANTIC
printf("CompileExp::semantic('%s')\n", toChars());
#endif
UnaExp::semantic(sc);
e1 = e1->ctfeSemantic(sc);
e1 = resolveProperties(sc, e1);
if (e1->op == TOKerror)
return e1;
Expand Down Expand Up @@ -6616,7 +6650,7 @@ Expression *FileExp::semantic(Scope *sc)
#if LOGSEMANTIC
printf("FileExp::semantic('%s')\n", toChars());
#endif
UnaExp::semantic(sc);
e1 = e1->ctfeSemantic(sc);
e1 = resolveProperties(sc, e1);
e1 = e1->ctfeInterpret();
if (e1->op != TOKstring)
Expand Down Expand Up @@ -8371,12 +8405,12 @@ Expression *CallExp::semantic(Scope *sc)
return new ErrorExp();
}

if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug))
if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug) && !sc->needctfe)
{
if (sc->func->setImpure())
error("pure function '%s' cannot call impure %s '%s'", sc->func->toPrettyChars(), p, e1->toChars());
}
if (sc->func && tf->trust <= TRUSTsystem)
if (sc->func && tf->trust <= TRUSTsystem && !sc->needctfe)
{
if (sc->func->setUnsafe())
error("safe function '%s' cannot call system %s '%s'", sc->func->toPrettyChars(), p, e1->toChars());
Expand Down Expand Up @@ -9557,14 +9591,22 @@ Expression *SliceExp::semantic(Scope *sc)
}

if (lwr)
{ lwr = lwr->semantic(sc2);
{
if (t->ty == Ttuple)
lwr = lwr->ctfeSemantic(sc2);
else
lwr = lwr->semantic(sc2);
lwr = resolveProperties(sc2, lwr);
lwr = lwr->implicitCastTo(sc2, Type::tsize_t);
if (lwr->type == Type::terror)
goto Lerr;
}
if (upr)
{ upr = upr->semantic(sc2);
{
if (t->ty == Ttuple)
upr = upr->ctfeSemantic(sc2);
else
upr = upr->semantic(sc2);
upr = resolveProperties(sc2, upr);
upr = upr->implicitCastTo(sc2, Type::tsize_t);
if (upr->type == Type::terror)
Expand Down Expand Up @@ -10038,7 +10080,10 @@ Expression *IndexExp::semantic(Scope *sc)
sc = sc->push(sym);
}

e2 = e2->semantic(sc);
if (t1->ty == Ttuple)
e2 = e2->ctfeSemantic(sc);
else
e2 = e2->semantic(sc);
e2 = resolveProperties(sc, e2);
if (e2->type == Type::terror)
goto Lerr;
Expand Down
1 change: 1 addition & 0 deletions src/expression.h
Expand Up @@ -113,6 +113,7 @@ struct Expression : Object
virtual int apply(apply_fp_t fp, void *param);
virtual Expression *semantic(Scope *sc);
Expression *trySemantic(Scope *sc);
Expression *ctfeSemantic(Scope *sc);

int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression()

Expand Down
6 changes: 3 additions & 3 deletions src/iasm.c
Expand Up @@ -3671,7 +3671,7 @@ STATIC code *asm_db_parse(OP *pop)

case TOKidentifier:
{ Expression *e = new IdentifierExp(asmstate.loc, asmtok->ident);
e = e->semantic(asmstate.sc);
e = e->ctfeSemantic(asmstate.sc);
e = e->ctfeInterpret();
if (e->op == TOKint64)
{ dt.ul = e->toInteger();
Expand Down Expand Up @@ -3747,7 +3747,7 @@ int asm_getnum()
Expression *e;

e = new IdentifierExp(asmstate.loc, asmtok->ident);
e = e->semantic(asmstate.sc);
e = e->ctfeSemantic(asmstate.sc);
e = e->ctfeInterpret();
i = e->toInteger();
v = (int) i;
Expand Down Expand Up @@ -4458,7 +4458,7 @@ STATIC OPND *asm_primary_exp()
break;
}
}
e = e->semantic(asmstate.sc);
e = e->ctfeSemantic(asmstate.sc);
e = e->ctfeInterpret();
if (e->isConst())
{
Expand Down
7 changes: 5 additions & 2 deletions src/init.c
Expand Up @@ -558,7 +558,7 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, NeedInterpret needIn
{
Expression *idx = index[i];
if (idx)
{ idx = idx->semantic(sc);
{ idx = idx->ctfeSemantic(sc);
idx = idx->ctfeInterpret();
index[i] = idx;
length = idx->toInteger();
Expand Down Expand Up @@ -942,7 +942,10 @@ bool arrayHasNonConstPointers(Expressions *elems)
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret)
{
//printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
exp = exp->semantic(sc);
if (needInterpret)
exp = exp->ctfeSemantic(sc);
else
exp = exp->semantic(sc);
exp = resolveProperties(sc, exp);
if (exp->op == TOKerror)
return this;
Expand Down