diff --git a/src/expression.c b/src/expression.c index 18c36e1e90fd..411b8645d692 100644 --- a/src/expression.c +++ b/src/expression.c @@ -1367,17 +1367,23 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) * requiring each function in between to be impure. */ Dsymbol *vparent = v->toParent2(); - for (Dsymbol *s = sc->func; s; s = s->toParent2()) + Dsymbol *s = sc->func, *snext = s->toParent2(); + // Make sure we're really finding parent *functions*, not parent + // class. + if (vparent->isFuncDeclaration() || snext != vparent) { - if (s == vparent) - break; - FuncDeclaration *ff = s->isFuncDeclaration(); - if (!ff) - break; - if (ff->setImpure()) - { error("pure nested function '%s' cannot access mutable data '%s'", - ff->toChars(), v->toChars()); - break; + for (; s; s = s->toParent2()) + { + if (s == vparent) + break; + FuncDeclaration *ff = s->isFuncDeclaration(); + if (!ff) + break; + if (ff->setImpure()) + { error("pure nested function '%s' cannot access mutable data '%s'", + ff->toChars(), v->toChars()); + break; + } } } } diff --git a/src/func.c b/src/func.c index 1a5a3a474f51..47c9be3eb1ae 100644 --- a/src/func.c +++ b/src/func.c @@ -2676,9 +2676,9 @@ enum PURE FuncDeclaration::isPure() TypeFunction *tf = (TypeFunction *)type; if (flags & FUNCFLAGpurityInprocess) setImpure(); - enum PURE purity = tf->purity; - if (purity == PUREfwdref) + if (tf->purity == PUREfwdref) tf->purityLevel(); + enum PURE purity = tf->purity; if (purity > PUREweak && needThis()) { // The attribute of the 'this' reference affects purity strength if (type->mod & (MODimmutable | MODwild)) @@ -2688,6 +2688,9 @@ enum PURE FuncDeclaration::isPure() else purity = PUREweak; } + tf->purity = purity; + // ^ This rely on the current situation that every FuncDeclaration has a + // unique TypeFunction. return purity; } diff --git a/test/runnable/xtest46.d b/test/runnable/xtest46.d index 6b8224c72674..2fdc0bd53940 100644 --- a/test/runnable/xtest46.d +++ b/test/runnable/xtest46.d @@ -3192,6 +3192,64 @@ pure int test4031() /***************************************************/ +struct S6230 { + int p; + int q() const pure { + return p; + } + void r() pure { + p = 231; + } +} +class C6230 { + int p; + int q() const pure { + return p; + } + void r() pure { + p = 552; + } +} +int q6230(ref const S6230 s) pure { // <-- Currently OK + return s.p; +} +int q6230(ref const C6230 c) pure { // <-- Currently OK + return c.p; +} +void r6230(ref S6230 s) pure { + s.p = 244; +} +void r6230(ref C6230 c) pure { + c.p = 156; +} +bool test6230pure() pure { + auto s = S6230(4); + assert(s.p == 4); + assert(q6230(s) == 4); + assert(s.q == 4); + + auto c = new C6230; + c.p = 6; + assert(q6230(c) == 6); + assert(c.q == 6); + + r6230(s); + assert(s.p == 244); + s.r(); + assert(s.p == 231); + + r6230(c); + assert(c.p == 156); + c.r(); + assert(c.p == 552); + + return true; +} +void test6230() { + assert(test6230pure()); +} + + int main() { test1(); @@ -3353,6 +3411,7 @@ int main() test4258(); test4963(); test4031(); + test6230(); printf("Success\n"); return 0;