Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #95 from 9rnsr/check_assignable
Issue 5327 & 2625 struct is assignable if all of fields are assignable
  • Loading branch information
WalterBright committed Jun 12, 2011
2 parents 0af1eb8 + 9ef7453 commit 3652978
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 5 deletions.
4 changes: 2 additions & 2 deletions src/expression.c
Expand Up @@ -8999,7 +8999,7 @@ Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e)
modifiable = 1;
if (e1->op == TOKstring)
error("string literals are immutable");
if (type && !type->isMutable())
if (type && (!type->isMutable() || !type->isAssignable()))
error("%s isn't mutable", e->toChars());
Type *t1 = e1->type->toBasetype();
if (t1->ty == Taarray)
Expand Down Expand Up @@ -9442,7 +9442,7 @@ Expression *AssignExp::semantic(Scope *sc)
else if (e1->op == TOKslice)
{
Type *tn = e1->type->nextOf();
if (tn && !tn->isMutable() && op != TOKconstruct)
if (op == TOKassign && tn && (!tn->isMutable() || !tn->isAssignable()))
{ error("slice %s is not mutable", e1->toChars());
return new ErrorExp();
}
Expand Down
27 changes: 24 additions & 3 deletions src/mtype.c
Expand Up @@ -7183,15 +7183,36 @@ int TypeStruct::needsDestruction()

int TypeStruct::isAssignable()
{
int assignable = TRUE;
unsigned offset;

/* If any of the fields are const or invariant,
* then one cannot assign this struct.
*/
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
if (v->isConst() || v->isImmutable())
return FALSE;
//printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind());
if (i == 0)
;
else if (v->offset == offset)
{
/* If some fields of anonymous union are assignable,
* then totally assignable
*/
if (assignable)
return TRUE;
}
else
{
if (!assignable)
return FALSE;
}
assignable = v->type->isMutable() && v->type->isAssignable();
offset = v->offset;
//printf(" -> assignable = %d\n", assignable);
}
return TRUE;

return assignable;
}

int TypeStruct::hasPointers()
Expand Down
146 changes: 146 additions & 0 deletions test/runnable/assignable.d
@@ -0,0 +1,146 @@
import std.c.stdio;

template TypeTuple(T...){ alias T TypeTuple; }

/***************************************************/
// 2625

struct Pair {
immutable uint g1;
uint g2;
}

void test1() {
Pair[1] stuff;
static assert(!__traits(compiles, (stuff[0] = Pair(1, 2))));
}

/***************************************************/
// 5327

struct ID
{
immutable int value;
}

struct Data
{
ID id;
}
void test2()
{
Data data = Data(ID(1));
immutable int* val = &data.id.value;
static assert(!__traits(compiles, data = Data(ID(2))));
}

/***************************************************/

struct S31A
{
union
{
immutable int field1;
immutable int field2;
}

enum result = false;
}
struct S31B
{
union
{
immutable int field1;
int field2;
}

enum result = true;
}
struct S31C
{
union
{
int field1;
immutable int field2;
}

enum result = true;
}
struct S31D
{
union
{
int field1;
int field2;
}

enum result = true;
}

struct S32A
{
int dummy0;
union
{
immutable int field1;
int field2;
}

enum result = true;
}
struct S32B
{
immutable int dummy0;
union
{
immutable int field1;
int field2;
}

enum result = false;
}


struct S32C
{
union
{
immutable int field1;
int field2;
}
int dummy1;

enum result = true;
}
struct S32D
{
union
{
immutable int field1;
int field2;
}
immutable int dummy1;

enum result = false;
}

void test3()
{
foreach (S; TypeTuple!(S31A,S31B,S31C,S31D, S32A,S32B,S32C,S32D))
{
S s;
static assert(__traits(compiles, s = s) == S.result);
}
}

/***************************************************/

int main()
{
test1();
test2();
test3();

printf("Success\n");
return 0;
}

2 comments on commit 3652978

@WalterBright
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an immutable member of an anonymous union makes the whole union not assignable. Immutable data may not change, and having a union cannot be used to break that guarantee.

@WalterBright
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see the union thing is to support the Rebindable template.

Please sign in to comment.