Skip to content

Commit

Permalink
Merge pull request #3085 from klickverbot/pure-return-immutable
Browse files Browse the repository at this point in the history
pure -> immutable fixes
  • Loading branch information
MartinNowak committed Jan 26, 2014
2 parents 5763f78 + 855e03a commit 01ca07b
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 62 deletions.
21 changes: 0 additions & 21 deletions src/cast.c
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/expression.h
Expand Up @@ -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);
Expand Down
75 changes: 35 additions & 40 deletions src/func.c
Expand Up @@ -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
{
Expand All @@ -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;
Expand All @@ -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;
}

/********************************************
Expand Down
21 changes: 21 additions & 0 deletions 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!!!
}
13 changes: 13 additions & 0 deletions 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];
}
15 changes: 15 additions & 0 deletions 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';
}
22 changes: 22 additions & 0 deletions 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';
}

0 comments on commit 01ca07b

Please sign in to comment.