diff --git a/src/cast.c b/src/cast.c index 7208fc11901c..2d1ad42fe289 100644 --- a/src/cast.c +++ b/src/cast.c @@ -610,27 +610,6 @@ MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) return Expression::implicitConvTo(t); } -Expression *CallExp::implicitCastTo(Scope *sc, Type *t) -{ - //printf("CallExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); - - /* Allow the result of strongly pure functions to - * convert to immutable - */ - if (f && f->isolateReturn() && - type->immutableOf()->equals(t->immutableOf())) - { - /* Avoid emitting CastExp for: - * T[] make() pure { ... } - * immutable T[] arr = make(); // unique return - */ - Expression *e = copy(); - e->type = t; - return e; - } - return Expression::implicitCastTo(sc, t); -} - MATCH CallExp::implicitConvTo(Type *t) { #if 0 diff --git a/src/expression.h b/src/expression.h index 5a7d2686ab0d..46a20f98847d 100644 --- a/src/expression.h +++ b/src/expression.h @@ -1103,7 +1103,6 @@ class CallExp : public UnaExp int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *addDtorHook(Scope *sc); - Expression *implicitCastTo(Scope *sc, Type *t); MATCH implicitConvTo(Type *t); Expression *doInline(InlineDoState *ids); diff --git a/src/func.c b/src/func.c index fc1fb75952e7..093830f3ca59 100644 --- a/src/func.c +++ b/src/func.c @@ -3294,32 +3294,35 @@ Type *getIndirection(Type *t) } /************************************** - * Traverse this and t, and then check the indirections convertibility. + * Returns true if memory reachable through a reference B to a value of type tb, + * which has been constructed with a reference A to a value of type ta + * available, can alias memory reachable from A based on the types involved + * (either directly or via any number of indirections). + * + * Note that this relation is not symmetric in the two arguments. For example, + * a const(int) reference can point to a pre-existing int, but not the other + * way round. */ - -int traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool a2b = true) +bool traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool reversePass = false) { - if (a2b) // check ta appears in tb + Type *source = ta; + Type *target = tb; + if (reversePass) { - //printf("\ttraverse(1) %s appears in %s\n", ta->toChars(), tb->toChars()); - if (ta->constConv(tb)) - return 1; - else if (ta->immutableOf()->equals(tb->immutableOf())) - return 0; - else if (tb->ty == Tvoid && MODimplicitConv(ta->mod, tb->mod)) - return 1; - } - else // check tb appears in ta - { - //printf("\ttraverse(2) %s appears in %s\n", tb->toChars(), ta->toChars()); - if (tb->constConv(ta)) - return 1; - else if (tb->immutableOf()->equals(ta->immutableOf())) - return 0; - else if (ta->ty == Tvoid && MODimplicitConv(tb->mod, ta->mod)) - return 1; + source = tb; + target = ta; } + if (source->constConv(target)) + return true; + else if (target->ty == Tvoid && MODimplicitConv(source->mod, target->mod)) + return true; + + // No direct match, so try breaking up one of the types (starting with tb). + Type *tbb = tb->toBasetype()->baseElemOf(); + if (tbb != tb) + return traverseIndirections(ta, tbb, p, reversePass); + // context date to detect circular look up struct Ctxt { @@ -3328,15 +3331,10 @@ int traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool a2b = true) }; Ctxt *ctxt = (Ctxt *)p; - Type *tbb = tb->toBasetype(); - if (tbb != tb) - return traverseIndirections(ta, tbb, ctxt, a2b); - - tb = tb->baseElemOf(); if (tb->ty == Tclass || tb->ty == Tstruct) { for (Ctxt *c = ctxt; c; c = c->prev) - if (tb == c->type) return 0; + if (tb == c->type) return false; Ctxt c; c.prev = ctxt; c.type = tb; @@ -3346,31 +3344,28 @@ int traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool a2b = true) { VarDeclaration *v = sym->fields[i]; Type *tprmi = v->type->addMod(tb->mod); - if (!(v->storage_class & STCref)) - tprmi = getIndirection(tprmi); - if (!tprmi) - continue; - //printf("\ttb = %s, tprmi = %s\n", tb->toChars(), tprmi->toChars()); - if (traverseIndirections(ta, tprmi, &c, a2b)) - return 1; + if (traverseIndirections(ta, tprmi, &c, reversePass)) + return true; } } else if (tb->ty == Tarray || tb->ty == Taarray || tb->ty == Tpointer) { Type *tind = tb->nextOf(); - if (traverseIndirections(ta, tind, ctxt, a2b)) - return 1; + if (traverseIndirections(ta, tind, ctxt, reversePass)) + return true; } else if (tb->hasPointers()) { // FIXME: function pointer/delegate types should be considered. - return 1; + return true; } - if (a2b) - return traverseIndirections(tb, ta, ctxt, false); - return 0; + // Still no match, so try breaking up ta if we have note done so yet. + if (!reversePass) + return traverseIndirections(tb, ta, ctxt, true); + + return false; } /******************************************** diff --git a/test/fail_compilation/fail11503a.d b/test/fail_compilation/fail11503a.d new file mode 100644 index 000000000000..28f7befdf91b --- /dev/null +++ b/test/fail_compilation/fail11503a.d @@ -0,0 +1,21 @@ +struct S +{ + immutable(S)* s; + this(int) immutable pure + { + s = &this; + } + int data; +} + +immutable(S)* makes() pure +{ + return new immutable S(0); +} + +void main() +{ + S* s = makes(); // s is mutable and contains an immutable reference to itself + //s.s.data = 7; // this is immutable + s.data = 3; // but this is not!!! +} diff --git a/test/fail_compilation/fail11503b.d b/test/fail_compilation/fail11503b.d new file mode 100644 index 000000000000..80549de8e6ca --- /dev/null +++ b/test/fail_compilation/fail11503b.d @@ -0,0 +1,13 @@ +immutable int[] x = [1, 2, 3]; + +auto makes() pure +{ + return x; +} + +int main() +{ + auto a = x; + int[] b = makes(); + return b[1]; +} diff --git a/test/fail_compilation/fail11503c.d b/test/fail_compilation/fail11503c.d new file mode 100644 index 000000000000..dc45eefc0939 --- /dev/null +++ b/test/fail_compilation/fail11503c.d @@ -0,0 +1,15 @@ +struct Data +{ + char[256] buffer; + @property const(char)[] filename() const pure nothrow + { + return buffer[]; + } +} + +void main() +{ + Data d; + string f = d.filename; + d.buffer[0] = 'a'; +} diff --git a/test/fail_compilation/fail11503d.d b/test/fail_compilation/fail11503d.d new file mode 100644 index 000000000000..d96e2a8b249a --- /dev/null +++ b/test/fail_compilation/fail11503d.d @@ -0,0 +1,22 @@ +struct Data2 +{ + char buffer; +} + +@property const(char)[] filename(const ref Data2 d) pure nothrow +{ + return (&d.buffer)[0 .. 1]; +} + +@property const(char)[] filename2(const Data2* d) pure nothrow +{ + return (&d.buffer)[0 .. 1]; +} + +void main() +{ + Data2 d; + string f = d.filename; + string g = (&d).filename2; + d.buffer = 'a'; +}