diff --git a/src/mtype.d b/src/mtype.d index 940b4a66828f..2af0d8c6cc04 100644 --- a/src/mtype.d +++ b/src/mtype.d @@ -6456,6 +6456,7 @@ extern (C++) final class TypeFunction : TypeNext } /******************************************** + * Set 'purity' field of 'this'. * Do this lazily, as the parameter types might be forward referenced. */ void purityLevel() @@ -6464,43 +6465,24 @@ extern (C++) final class TypeFunction : TypeNext if (tf.purity != PUREfwdref) return; - /* Evaluate what kind of purity based on the modifiers for the parameters + /* Determine purity level based on mutability of t + * and whether it is a 'ref' type or not. */ - tf.purity = PUREstrong; // assume strong until something weakens it - - size_t dim = Parameter.dim(tf.parameters); - if (!dim) - return; - for (size_t i = 0; i < dim; i++) + static PURE purityOfType(bool isref, Type t) { - Parameter fparam = Parameter.getNth(tf.parameters, i); - Type t = fparam.type; - if (!t) - continue; - - if (fparam.storageClass & (STClazy | STCout)) - { - tf.purity = PUREweak; - break; - } - if (fparam.storageClass & STCref) + if (isref) { if (t.mod & MODimmutable) - continue; + return PUREstrong; if (t.mod & (MODconst | MODwild)) - { - tf.purity = PUREconst; - continue; - } - tf.purity = PUREweak; - break; + return PUREconst; + return PUREweak; } t = t.baseElemOf(); - if (!t.hasPointers()) - continue; - if (t.mod & MODimmutable) - continue; + + if (!t.hasPointers() || t.mod & MODimmutable) + return PUREstrong; /* Accept immutable(T)[] and immutable(T)* as being strongly pure */ @@ -6508,29 +6490,69 @@ extern (C++) final class TypeFunction : TypeNext { Type tn = t.nextOf().toBasetype(); if (tn.mod & MODimmutable) - continue; + return PUREstrong; if (tn.mod & (MODconst | MODwild)) - { - tf.purity = PUREconst; - continue; - } + return PUREconst; } /* The rest of this is too strict; fix later. * For example, the only pointer members of a struct may be immutable, * which would maintain strong purity. + * (Just like for dynamic arrays and pointers above.) */ if (t.mod & (MODconst | MODwild)) - { - tf.purity = PUREconst; + return PUREconst; + + /* Should catch delegates and function pointers, and fold in their purity + */ + return PUREweak; + } + + purity = PUREstrong; // assume strong until something weakens it + + /* Evaluate what kind of purity based on the modifiers for the parameters + */ + const dim = Parameter.dim(tf.parameters); + Lloop: foreach (i; 0 .. dim) + { + Parameter fparam = Parameter.getNth(tf.parameters, i); + Type t = fparam.type; + if (!t) continue; + + if (fparam.storageClass & (STClazy | STCout)) + { + purity = PUREweak; + break; } + switch (purityOfType((fparam.storageClass & STCref) != 0, t)) + { + case PUREweak: + purity = PUREweak; + break Lloop; // since PUREweak, no need to check further - /* Should catch delegates and function pointers, and fold in their purity + case PUREconst: + purity = PUREconst; + continue; + + case PUREstrong: + continue; + + default: + assert(0); + } + } + + if (purity > PUREweak && tf.nextOf()) + { + /* Adjust purity based on mutability of return type. + * https://issues.dlang.org/show_bug.cgi?id=15862 */ - tf.purity = PUREweak; // err on the side of too strict - break; + const purity2 = purityOfType(tf.isref, tf.nextOf()); + if (purity2 < purity) + purity = purity2; } + tf.purity = purity; } /******************************************** diff --git a/test/runnable/test15862.d b/test/runnable/test15862.d new file mode 100644 index 000000000000..09b9aff509c4 --- /dev/null +++ b/test/runnable/test15862.d @@ -0,0 +1,66 @@ +// https://issues.dlang.org/show_bug.cgi?id=15862 + +/* +PERMUTE_ARGS: +REQUIRED_ARGS: -O -release +*/ + + +int* p() pure nothrow {return new int;} +int[] a() pure nothrow {return [0];} +Object o() pure nothrow {return new Object;} + +immutable(int)* pn() pure nothrow {return new int;} +immutable(int)[] an() pure nothrow {return [0];} +immutable(Object) on() pure nothrow {return new Object;} + +auto pa() pure nothrow {return new int;} +auto pb() pure nothrow {return cast(immutable(int)*)(new int);} + +void main() +{ + { + int* p1 = p(); + int* p2 = p(); + + if (p1 is p2) assert(0); + + int[] a1 = a(); + int[] a2 = a(); + + if (a1 is a2) assert(0); + + Object o1 = o(); + Object o2 = o(); + + if (o1 is o2) assert(0); + } + { + auto p1 = pn(); + auto p2 = pn(); + + if (p1 !is p2) assert(0); + + auto a1 = an(); + auto a2 = an(); + + if (a1 !is a2) assert(0); + + auto o1 = on(); + auto o2 = on(); + + if (o1 !is o2) assert(0); + } + { + auto p1 = pa(); + auto p2 = pa(); + + if (p1 is p2) assert(0); + } + { + auto p1 = pb(); + auto p2 = pb(); + + if (p1 !is p2) assert(0); + } +}