Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

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

Merged
merged 1 commit into from

3 participants

@yebblies
Collaborator

When running semantic on an expression used anywhere that forces compile time evaluation, use a scope flag to prevent purity and safety checks on function calls.
This allows more functions to be inferred @safe/pure.

http://d.puremagic.com/issues/show_bug.cgi?id=6169

@donc
Collaborator

There's a huge similarity between this bug, and the gagging that occurs in speculative template instantiation (bug 4269, for example, which I'm currently working on). In both cases, semantic is run in a different mode, and a certain subset of errors need to be suppressed/ignored. I think they can both be treated in the same way.

@yebblies
Collaborator

Yeah, this is a new type of gagging (eek) but as it can't leak outside expressions there hopefully won't be too many problems with it. The only ways I could think of for solving 4269 is to make semantic completely reversible for declarations or to suspend gagging when evaulating non-speculative declarations. The first options requires lots of work and has hundreds of corner cases, and the second doesn't work inside speculative declarations... I'll be interested to see your solution.

@donc
Collaborator

I'm taking the second approach: ungag if non-speculative, when semantic is called from a speculative context.

@yebblies
Collaborator

Ok, but I don't know how this will work for declarations that must be evaluated speculatively - basically anything can be inside a template declaration, and unless semantic can be re-run how can the errors be detected later?
eg

template Templ(T)
{
    static assert(is(T == int));
    int fun() {}
}
static assert(!__traits(compiles, Templ!(long).fun()));
enum x = Templ!(long).fun(); // semantic has already failed

The issue here isn't that semantic is being run gagged when it shouldn't be, it's that to generate the correct errors semantic has to be run again.

@donc
Collaborator

Yeah, I dealt with that in a previous pull request. TemplateInstance has a member for speculative errors. If an error occurs, that counter gets updated. But it currently only applies to errors inside function bodies. It needs to be extended to work on other declarations.

@yebblies
Collaborator

Won't that result in a generic 'errors instantiating' message rather than the specifics? I guess it would change this bug from accepts-invalid to a massive diagnostic problem.

@donc
Collaborator

No. If there are semantic speculative errors, and a non-speculative instantiation is requested, the existing instantiation is discarded.
Code from TemplateInstance::semantic()

   // If both this and the previous instantiation were speculative,
    // use the number of errors that happened last time.
    if (inst->speculative && global.gag)
    {
        global.errors += inst->errors;
        global.gaggedErrors += inst->errors;
    }

    // If the first instantiation was speculative, but this is not:
    if (inst->speculative && !global.gag)
    {
        // If the first instantiation had failed, re-run semantic,
        // so that error messages are shown.
        if (inst->errors)
            goto L1;
        // It had succeeded, mark it is a non-speculative instantiation,
        // and reuse it.
        inst->speculative = 0;
    }
@yebblies
Collaborator

Updated to match Don's recent ctfeInterpret changes.

There is one change: Runtime values in case statements are no longer allowed.

@donc
Collaborator

There is one change: Runtime values in case statements are no longer allowed.

Please undo that. Although I would love for that to happen, it's a language change so it needs to be in its own pull request.

@yebblies
Collaborator

Ok, I'll leave the original behavior for case variables.

@yebblies
Collaborator

Done.

@andralex
Owner

OK to assign @donc to this? Please advise. I'm uneasy about two things: (a) inferring pure for regular functions makes for a big difference when compiling things separately vs. not. Not sure how bad that is. (b) disallowing runtime values for switch breaks code. This is a big one. Thoughts?

@donc donc was assigned
@donc
Collaborator

The "disallowing runtime values" was removed from the pull request as part of the "restore case variables" commit.
The "inferring pure" part doesn't make a difference for separate compilation, it's simply the fact that whenever any compile-time constant is used, it is never impure, even if it was created by CTFE. If you know an expression is a compile-time literal, you don't need to analyze it further.

@yebblies
Collaborator

@andralex
a) This allows more functions to be inferred as pure by excluding ctfe expressions from checks, as nothing run at compile time can break run-time purity and safety. It does not change the circumstances is which a function has purity inference run on it.
b) While I hate case variables with a passion, they are no longer removed by this pull request. I've updated the description to reflect that.

@braddr braddr referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@yebblies
Collaborator

Updated.

@yebblies
Collaborator

Updated again.

@yebblies yebblies Fix Issue 6169 - [CTFE] pure functions cannot compute constants using…
… functions not marked as pure

When running semantic on an expression used anywhere that forces compile time evaluation, use a scope flag to prevent purity and safety checks on function calls.
This allows better purity/safety inferrence as well.
42d1af1
@donc donc merged commit 15a5783 into D-Programming-Language:master
@yebblies yebblies deleted the yebblies:issue6169 branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 2, 2013
  1. @yebblies

    Fix Issue 6169 - [CTFE] pure functions cannot compute constants using…

    yebblies authored
    … functions not marked as pure
    
    When running semantic on an expression used anywhere that forces compile time evaluation, use a scope flag to prevent purity and safety checks on function calls.
    This allows better purity/safety inferrence as well.
This page is out of date. Refresh to see the latest.
View
10 src/attrib.c
@@ -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();
@@ -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;
@@ -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;
@@ -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)
@@ -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();
View
2  src/cond.c
@@ -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())
View
12 src/declaration.c
@@ -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)
@@ -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--;
@@ -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();
View
14 src/enum.c
@@ -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)
{
@@ -299,7 +299,7 @@ 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();
}
@@ -307,14 +307,14 @@ void EnumDeclaration::semantic(Scope *sc)
// 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();
@@ -322,7 +322,7 @@ void EnumDeclaration::semantic(Scope *sc)
{
// 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());
@@ -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;
View
71 src/expression.c
@@ -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());
@@ -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'",
@@ -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())
@@ -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);
@@ -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,
@@ -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;
@@ -5479,7 +5511,9 @@ Expression *FuncExp::semantic(Scope *sc)
}
fd->tookAddressOf++;
}
- return this;
+Ldone:
+ sc->needctfe = needctfe;
+ return e;
}
// used from CallExp::semantic()
@@ -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;
@@ -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)
@@ -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());
@@ -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)
@@ -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;
View
1  src/expression.h
@@ -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()
View
6 src/iasm.c
@@ -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();
@@ -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;
@@ -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())
{
View
7 src/init.c
@@ -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();
@@ -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;
View
12 src/mtype.c
@@ -3599,12 +3599,12 @@ Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
sym->parent = sc->scopesym;
sc = sc->push(sym);
- exp = exp->semantic(sc);
+ exp = exp->ctfeSemantic(sc);
sc->pop();
}
else
- exp = exp->semantic(sc);
+ exp = exp->ctfeSemantic(sc);
return exp;
}
@@ -3614,7 +3614,7 @@ Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
sym->parent = sc->scopesym;
sc = sc->push(sym);
- exp = exp->semantic(sc);
+ exp = exp->ctfeSemantic(sc);
sc->pop();
return exp;
@@ -3643,7 +3643,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol
sym->parent = sc->scopesym;
sc = sc->push(sym);
- dim = dim->semantic(sc);
+ dim = dim->ctfeSemantic(sc);
dim = dim->ctfeInterpret();
uinteger_t d = dim->toUInteger();
@@ -9132,11 +9132,11 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol
sym->parent = sc->scopesym;
sc = sc->push(sym);
- lwr = lwr->semantic(sc);
+ lwr = lwr->ctfeSemantic(sc);
lwr = lwr->ctfeInterpret();
uinteger_t i1 = lwr->toUInteger();
- upr = upr->semantic(sc);
+ upr = upr->ctfeSemantic(sc);
upr = upr->ctfeInterpret();
uinteger_t i2 = upr->toUInteger();
View
2  src/scope.c
@@ -74,6 +74,7 @@ Scope::Scope()
this->nofree = 0;
this->noctor = 0;
this->noaccesscheck = 0;
+ this->needctfe = 0;
this->intypeof = 0;
this->speculative = 0;
this->parameterSpecialization = 0;
@@ -123,6 +124,7 @@ Scope::Scope(Scope *enclosing)
this->nofree = 0;
this->noctor = enclosing->noctor;
this->noaccesscheck = enclosing->noaccesscheck;
+ this->needctfe = enclosing->needctfe;
this->intypeof = enclosing->intypeof;
this->speculative = enclosing->speculative;
this->parameterSpecialization = enclosing->parameterSpecialization;
View
1  src/scope.h
@@ -68,6 +68,7 @@ struct Scope
bool speculative; // in __traits(compiles) or typeof(exp)
int parameterSpecialization; // if in template parameter specialization
int noaccesscheck; // don't do access checks
+ int needctfe; // inside a ctfe-only expression
unsigned callSuper; // primitive flow analysis for constructors
#define CSXthis_ctor 1 // called this()
View
14 src/statement.c
@@ -473,7 +473,7 @@ void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
Statements *CompileStatement::flatten(Scope *sc)
{
//printf("CompileStatement::flatten() %s\n", exp->toChars());
- exp = exp->semantic(sc);
+ exp = exp->ctfeSemantic(sc);
exp = resolveProperties(sc, exp);
exp = exp->ctfeInterpret();
if (exp->op == TOKerror)
@@ -2851,7 +2851,7 @@ Statement *PragmaStatement::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();
@@ -2883,7 +2883,7 @@ Statement *PragmaStatement::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;
@@ -2909,7 +2909,7 @@ Statement *PragmaStatement::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;
@@ -3241,7 +3241,7 @@ Statement *CaseStatement::semantic(Scope *sc)
{ SwitchStatement *sw = sc->sw;
//printf("CaseStatement::semantic() %s\n", toChars());
- exp = exp->semantic(sc);
+ exp = exp->ctfeSemantic(sc);
exp = resolveProperties(sc, exp);
if (sw)
{
@@ -3358,12 +3358,12 @@ Statement *CaseRangeStatement::semantic(Scope *sc)
if (sw->isFinal)
error("case ranges not allowed in final switch");
- first = first->semantic(sc);
+ first = first->ctfeSemantic(sc);
first = resolveProperties(sc, first);
first = first->implicitCastTo(sc, sw->condition->type);
first = first->ctfeInterpret();
- last = last->semantic(sc);
+ last = last->ctfeSemantic(sc);
last = resolveProperties(sc, last);
last = last->implicitCastTo(sc, sw->condition->type);
last = last->ctfeInterpret();
View
4 src/staticassert.c
@@ -55,7 +55,7 @@ void StaticAssert::semantic2(Scope *sc)
ScopeDsymbol *sd = new ScopeDsymbol();
sc = sc->push(sd);
sc->flags |= SCOPEstaticassert;
- Expression *e = exp->semantic(sc);
+ Expression *e = exp->ctfeSemantic(sc);
e = resolveProperties(sc, e);
sc = sc->pop();
if (!e->type->checkBoolean())
@@ -76,7 +76,7 @@ void StaticAssert::semantic2(Scope *sc)
{ HdrGenState hgs;
OutBuffer buf;
- msg = msg->semantic(sc);
+ msg = msg->ctfeSemantic(sc);
msg = resolveProperties(sc, msg);
msg = msg->ctfeInterpret();
hgs.console = 1;
View
2  src/struct.c
@@ -118,7 +118,7 @@ void AggregateDeclaration::semantic3(Scope *sc)
ti->semantic3(sc);
Dsymbol *s = ti->toAlias();
Expression *e = new DsymbolExp(0, s, 0);
- e = e->semantic(ti->tempdecl->scope);
+ e = e->ctfeSemantic(ti->tempdecl->scope);
e = e->ctfeInterpret();
getRTInfo = e;
}
View
20 src/template.c
@@ -845,9 +845,8 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti,
fd->vthis = fd->declareThis(paramscope, ad);
}
- e = e->semantic(sc);
+ e = e->ctfeSemantic(sc);
e = resolveProperties(sc, e);
-
if (e->op == TOKerror)
goto Lnomatch;
@@ -1907,7 +1906,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Scope *sc, Objec
fd->vthis = fd->declareThis(paramscope, ad);
}
- e = e->semantic(paramscope);
+ e = e->ctfeSemantic(paramscope);
e = resolveProperties(sc, e);
if (fd && fd->vthis)
@@ -4086,7 +4085,7 @@ Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o)
}
else if (ea)
{
- ea = ea->semantic(sc);
+ ea = ea->ctfeSemantic(sc);
o = ea->ctfeInterpret();
}
}
@@ -4402,7 +4401,7 @@ void TemplateValueParameter::semantic(Scope *sc)
if (specValue)
{ Expression *e = specValue;
- e = e->semantic(sc);
+ e = e->ctfeSemantic(sc);
e = e->implicitCastTo(sc, valType);
e = e->ctfeInterpret();
if (e->op == TOKint64 || e->op == TOKfloat64 ||
@@ -4414,7 +4413,7 @@ void TemplateValueParameter::semantic(Scope *sc)
if (defaultValue)
{ Expression *e = defaultValue;
- e = e->semantic(sc);
+ e = e->ctfeSemantic(sc);
e = e->implicitCastTo(sc, valType);
e = e->ctfeInterpret();
if (e->op == TOKint64)
@@ -4517,13 +4516,13 @@ MATCH TemplateValueParameter::matchArg(Scope *sc,
Expression *e = specValue;
- e = e->semantic(sc);
+ e = e->ctfeSemantic(sc);
e = resolveProperties(sc, e);
e = e->implicitCastTo(sc, vt);
e = e->ctfeInterpret();
ei = ei->syntaxCopy();
- ei = ei->semantic(sc);
+ ei = ei->ctfeSemantic(sc);
ei = ei->implicitCastTo(sc, vt);
ei = ei->ctfeInterpret();
//printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars());
@@ -5473,7 +5472,10 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f
{
Lexpr:
//printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
- ea = ea->semantic(sc);
+ if (flags & 1)
+ ea = ea->semantic(sc);
+ else
+ ea = ea->ctfeSemantic(sc);
if (flags & 1) // only used by __traits, must not interpret the args
ea = ea->optimize(WANTvalue);
else if (ea->op == TOKvar)
View
8 test/fail_compilation/failsafea.d
@@ -0,0 +1,8 @@
+
+void systemfunc() @system {}
+
+@safe
+void callingsystem()
+{
+ systemfunc();
+}
View
8 test/fail_compilation/failsafeb.d
@@ -0,0 +1,8 @@
+
+void function() @system sysfuncptr;
+
+@safe
+void callingsystem()
+{
+ sysfuncptr();
+}
View
9 test/fail_compilation/failsafec.d
@@ -0,0 +1,9 @@
+
+void delegate() @system sysdelegate;
+
+@safe
+void callingsystem()
+{
+ sysdelegate();
+}
+
View
8 test/runnable/Fix5140.d
@@ -55,8 +55,8 @@ void main(string[] args) nothrow
static assert(getTemplCallingFunc() == "Fix5140.main.__lambda1");
static assert(getCalleeFunc() == "imports.Fix5140a.getCalleeFunc");
- static assert(getCallingPrettyFunc() == "Fix5140.main.__lambda1(int x, int y) @system");
- static assert(getTemplCallingPrettyFunc() == "Fix5140.main.__lambda1(int x, int y) @system");
+ static assert(getCallingPrettyFunc() == "Fix5140.main.__lambda1(int x, int y)");
+ static assert(getTemplCallingPrettyFunc() == "Fix5140.main.__lambda1(int x, int y)");
static assert(getCalleePrettyFunc(1, 1.0) == "string imports.Fix5140a.getCalleePrettyFunc(int x, float y)");
};
funcLiteral(1, 2);
@@ -73,8 +73,8 @@ void main(string[] args) nothrow
static assert(getTemplCallingFunc() == "Fix5140.main.S.func!(\"foo\", int, symbol, int[],float[]).func");
static assert(getCalleeFunc() == "imports.Fix5140a.getCalleeFunc");
- static assert(getCallingPrettyFunc() == "void Fix5140.main.S.func!(\"foo\", int, symbol, int[],float[]).func(int x) const @system");
- static assert(getTemplCallingPrettyFunc() == "void Fix5140.main.S.func!(\"foo\", int, symbol, int[],float[]).func(int x) const @system");
+ static assert(getCallingPrettyFunc() == "void Fix5140.main.S.func!(\"foo\", int, symbol, int[],float[]).func(int x) const");
+ static assert(getTemplCallingPrettyFunc() == "void Fix5140.main.S.func!(\"foo\", int, symbol, int[],float[]).func(int x) const");
static assert(getCalleePrettyFunc(1, 1.0) == "string imports.Fix5140a.getCalleePrettyFunc(int x, float y)");
}
}
View
12 test/runnable/testsafe.d
@@ -170,18 +170,6 @@ void safeunions()
-void systemfunc() @system {}
-void function() @system sysfuncptr;
-void delegate() @system sysdelegate;
-
-@safe
-void callingsystem()
-{
- static assert(!__traits(compiles, systemfunc()));
- static assert(!__traits(compiles, sysfuncptr()));
- static assert(!__traits(compiles, sysdelegate()));
-}
-
@safe
void safeexception()
{
View
43 test/runnable/xtest46.d
@@ -2610,6 +2610,49 @@ void test129()
/***************************************************/
+
+auto ctfefunc6169() { return ";"; }
+enum ctfefptr6169 = &ctfefunc6169;
+int ctfefunc6169a() { return 1; }
+template x6169(string c) { alias int x6169; }
+template TT6169(T...) { alias T TT6169; }
+
+void test6169() pure @safe
+{
+ enum a = ctfefunc6169();
+ static b = ctfefunc6169();
+ x6169!(ctfefunc6169()) tt;
+ mixin(ctfefunc6169());
+ static if(ctfefunc6169()) {}
+ pragma(msg, ctfefunc6169());
+ enum xx
+ {
+ k = 0,
+ j = ctfefunc6169a()
+ }
+ auto g = mixin('"' ~ ctfefunc6169() ~ '"');
+ //auto h = import("testx.d" ~ false ? ctfefunc() : "");
+ alias TT6169!(int, int)[ctfefunc6169a()..ctfefunc6169a()] i;
+ alias TT6169!(int, int)[ctfefunc6169a()] j;
+ int[ctfefunc6169a()+1] k;
+ alias int[ctfefunc6169a()] l;
+ switch(1)
+ {
+ //case ctfefunc6169a(): // Can't do this because of case variables
+ case ctfefunc6169a()+1:
+ ..
+ case ctfefunc6169a()+2:
+ default:
+ break;
+ }
+ static assert(ctfefunc6169a());
+ void fun(int i : ctfefunc6169a() = ctfefunc6169a(), alias j)() if (ctfefunc6169a()) {}
+ fun!(ctfefunc6169a(), ctfefunc6169())();
+ enum z = ctfefptr6169();
+}
+
+/***************************************************/
+
const shared class C5107
{
int x;
Something went wrong with that request. Please try again.