From 42d1af1635fec1c43bbda6c4a3894e148ca6fc22 Mon Sep 17 00:00:00 2001 From: Daniel Murphy Date: Fri, 3 May 2013 09:15:40 +1000 Subject: [PATCH] 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. --- src/attrib.c | 10 ++--- src/cond.c | 2 +- src/declaration.c | 12 +++++- src/enum.c | 14 +++--- src/expression.c | 71 +++++++++++++++++++++++++------ src/expression.h | 1 + src/iasm.c | 6 +-- src/init.c | 7 ++- src/mtype.c | 12 +++--- src/scope.c | 2 + src/scope.h | 1 + src/statement.c | 14 +++--- src/staticassert.c | 4 +- src/struct.c | 2 +- src/template.c | 20 +++++---- test/fail_compilation/failsafea.d | 8 ++++ test/fail_compilation/failsafeb.d | 8 ++++ test/fail_compilation/failsafec.d | 9 ++++ test/runnable/Fix5140.d | 8 ++-- test/runnable/testsafe.d | 12 ------ test/runnable/xtest46.d | 43 +++++++++++++++++++ 21 files changed, 193 insertions(+), 73 deletions(-) create mode 100644 test/fail_compilation/failsafea.d create mode 100644 test/fail_compilation/failsafeb.d create mode 100644 test/fail_compilation/failsafec.d diff --git a/src/attrib.c b/src/attrib.c index 964467b0547e..c30ccfebf067 100644 --- a/src/attrib.c +++ b/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(); diff --git a/src/cond.c b/src/cond.c index 0e496704f3ba..1da4f3de9564 100644 --- a/src/cond.c +++ b/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()) diff --git a/src/declaration.c b/src/declaration.c index 02ea16c8f334..59f789730db2 100644 --- a/src/declaration.c +++ b/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(); diff --git a/src/enum.c b/src/enum.c index 67815177150e..bdf3952b3227 100644 --- a/src/enum.c +++ b/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; diff --git a/src/expression.c b/src/expression.c index 5050480b1e56..63b0395a86ff 100644 --- a/src/expression.c +++ b/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; diff --git a/src/expression.h b/src/expression.h index 83d6c33f077c..5674f30ce837 100644 --- a/src/expression.h +++ b/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() diff --git a/src/iasm.c b/src/iasm.c index d61a146cd76f..45a82a8eb3f1 100644 --- a/src/iasm.c +++ b/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()) { diff --git a/src/init.c b/src/init.c index 8659572b68c4..1762aff0cc5a 100644 --- a/src/init.c +++ b/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; diff --git a/src/mtype.c b/src/mtype.c index f9eb6e58712b..9bc89a00528c 100644 --- a/src/mtype.c +++ b/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(); diff --git a/src/scope.c b/src/scope.c index 4fb835bf8a06..23a9971ad5cb 100644 --- a/src/scope.c +++ b/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; diff --git a/src/scope.h b/src/scope.h index 247e3835d918..c7d31b56cd95 100644 --- a/src/scope.h +++ b/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() diff --git a/src/statement.c b/src/statement.c index 7db1f609fb02..bd03ee2c84ca 100644 --- a/src/statement.c +++ b/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(); diff --git a/src/staticassert.c b/src/staticassert.c index efc6b4ec73f9..8a69459eef65 100644 --- a/src/staticassert.c +++ b/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; diff --git a/src/struct.c b/src/struct.c index 054dc948db55..33cb328ac0f5 100644 --- a/src/struct.c +++ b/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; } diff --git a/src/template.c b/src/template.c index 261b665fb3df..3fe65b88ddb4 100644 --- a/src/template.c +++ b/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) diff --git a/test/fail_compilation/failsafea.d b/test/fail_compilation/failsafea.d new file mode 100644 index 000000000000..b2a3f227b0d1 --- /dev/null +++ b/test/fail_compilation/failsafea.d @@ -0,0 +1,8 @@ + +void systemfunc() @system {} + +@safe +void callingsystem() +{ + systemfunc(); +} diff --git a/test/fail_compilation/failsafeb.d b/test/fail_compilation/failsafeb.d new file mode 100644 index 000000000000..c04d9ee5dc72 --- /dev/null +++ b/test/fail_compilation/failsafeb.d @@ -0,0 +1,8 @@ + +void function() @system sysfuncptr; + +@safe +void callingsystem() +{ + sysfuncptr(); +} diff --git a/test/fail_compilation/failsafec.d b/test/fail_compilation/failsafec.d new file mode 100644 index 000000000000..8bcda913720e --- /dev/null +++ b/test/fail_compilation/failsafec.d @@ -0,0 +1,9 @@ + +void delegate() @system sysdelegate; + +@safe +void callingsystem() +{ + sysdelegate(); +} + diff --git a/test/runnable/Fix5140.d b/test/runnable/Fix5140.d index 86861b7765c9..ba73a33eb616 100644 --- a/test/runnable/Fix5140.d +++ b/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)"); } } diff --git a/test/runnable/testsafe.d b/test/runnable/testsafe.d index f556978f7fc1..4c4700f37fc5 100644 --- a/test/runnable/testsafe.d +++ b/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() { diff --git a/test/runnable/xtest46.d b/test/runnable/xtest46.d index f502a373cfd8..9bfe9806ad42 100644 --- a/test/runnable/xtest46.d +++ b/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;