Skip to content

Commit

Permalink
Merge pull request #3555 from 9rnsr/fix12749
Browse files Browse the repository at this point in the history
Issue 12749 - Constructor-local function allows multiple mutation of immutable member
  • Loading branch information
WalterBright committed May 31, 2014
2 parents 24224e0 + d1713bd commit d1beeaa
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 45 deletions.
3 changes: 2 additions & 1 deletion src/declaration.c
Expand Up @@ -156,7 +156,8 @@ int Declaration::checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int fl
}

if (v && (isCtorinit() || isField()))
{ // It's only modifiable if inside the right constructor
{
// It's only modifiable if inside the right constructor
if ((storage_class & (STCforeach | STCref)) == (STCforeach | STCref))
return 2;
return modifyFieldVar(loc, sc, v, e1) ? 2 : 1;
Expand Down
28 changes: 25 additions & 3 deletions src/expression.c
Expand Up @@ -2127,7 +2127,8 @@ Expression *Expression::modifiableLvalue(Scope *sc, Expression *e)
if (type->isMutable())
{
if (!type->isAssignable())
{ error("cannot modify struct %s %s with immutable members", toChars(), type->toChars());
{
error("cannot modify struct %s %s with immutable members", toChars(), type->toChars());
goto Lerror;
}
}
Expand Down Expand Up @@ -7559,16 +7560,37 @@ int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1)
if (!mustInit && var->type->isMutable() && e1->type->isMutable())
result = false;
else
::error(loc, "field '%s' initializing not allowed in loops or after labels", var->toChars());
{
const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
::error(loc, "%s field '%s' initialization is not allowed in loops or after labels", modStr, var->toChars());
}
}
sc->fieldinit[i] |= CSXthis_ctor;
}
else if (fd != sc->func)
{
if (var->type->isMutable())
result = false;
else if (sc->func->fes)
{
const char *p = var->isField() ? "field" : var->kind();
::error(loc, "%s %s '%s' initialization is not allowed in foreach loop",
MODtoChars(var->type->mod), p, var->toChars());
}
else
{
const char *p = var->isField() ? "field" : var->kind();
::error(loc, "%s %s '%s' initialization is not allowed in nested function '%s'",
MODtoChars(var->type->mod), p, var->toChars(), sc->func->toChars());
}
}
return result;
}
else
{
if (s)
{ s = s->toParent2();
{
s = s->toParent2();
continue;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/func.c
Expand Up @@ -1662,9 +1662,9 @@ void FuncDeclaration::semantic3(Scope *sc)
if (v->isCtorinit() && !v->type->isMutable() && cd)
error("missing initializer for %s field %s", MODtoChars(v->type->mod), v->toChars());
else if (v->storage_class & STCnodefaultctor)
error("field %s must be initialized in constructor", v->toChars());
::error(loc, "field %s must be initialized in constructor", v->toChars());
else if (v->type->needsNested())
error("field %s must be initialized in constructor, because it is nested struct", v->toChars());
::error(loc, "field %s must be initialized in constructor, because it is nested struct", v->toChars());
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion test/fail_compilation/diag12678.d
Expand Up @@ -3,7 +3,7 @@ TEST_OUTPUT:
---
fail_compilation/diag12678.d(19): Error: const field 'cf1' initialized multiple times
fail_compilation/diag12678.d(22): Error: immutable field 'if1' initialized multiple times
fail_compilation/diag12678.d(25): Error: field 'cf2' initializing not allowed in loops or after labels
fail_compilation/diag12678.d(25): Error: const field 'cf2' initialization is not allowed in loops or after labels
---
*/

Expand Down
62 changes: 62 additions & 0 deletions test/fail_compilation/fail12749.d
@@ -0,0 +1,62 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail12749.d(19): Error: immutable field 'inum' initialization is not allowed in foreach loop
fail_compilation/fail12749.d(20): Error: const field 'cnum' initialization is not allowed in foreach loop
fail_compilation/fail12749.d(25): Error: immutable field 'inum' initialization is not allowed in nested function 'set'
fail_compilation/fail12749.d(26): Error: const field 'cnum' initialization is not allowed in nested function 'set'
---
*/
struct S
{
immutable int inum;
const int cnum;

this(int i)
{
foreach (n; Aggr())
{
inum = i;
cnum = i;
}

void set(int i)
{
inum = i;
cnum = i;
}
}
}

/*
TEST_OUTPUT:
---
fail_compilation/fail12749.d(48): Error: immutable variable 'inum' initialization is not allowed in foreach loop
fail_compilation/fail12749.d(49): Error: const variable 'cnum' initialization is not allowed in foreach loop
fail_compilation/fail12749.d(54): Error: immutable variable 'inum' initialization is not allowed in nested function 'set'
fail_compilation/fail12749.d(55): Error: const variable 'cnum' initialization is not allowed in nested function 'set'
---
*/
immutable int inum;
const int cnum;
static this()
{
int i = 10;

foreach (n; Aggr())
{
inum = i;
cnum = i;
}

void set(int i)
{
inum = i;
cnum = i;
}
}

struct Aggr
{
int opApply(int delegate(int) dg) { return dg(1); }
}
55 changes: 40 additions & 15 deletions test/fail_compilation/fail9665a.d
Expand Up @@ -7,21 +7,7 @@
/+
TEST_OUTPUT:
---
fail_compilation/fail9665a.d(33): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(43): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(48): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(53): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(63): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(68): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(73): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(86): Error: field 'v' initializing not allowed in loops or after labels
fail_compilation/fail9665a.d(91): Error: field 'v' initializing not allowed in loops or after labels
fail_compilation/fail9665a.d(96): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(101): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(106): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(120): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(124): Error: immutable field 'w' initialized multiple times
fail_compilation/fail9665a.d(137): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(19): Error: immutable field 'v' initialized multiple times
---
+/
struct S1A
Expand All @@ -34,6 +20,14 @@ struct S1A
}
}

/+
TEST_OUTPUT:
---
fail_compilation/fail9665a.d(37): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(42): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(47): Error: immutable field 'v' initialized multiple times
---
+/
struct S1B
{
immutable int v;
Expand All @@ -54,6 +48,14 @@ struct S1B
}
}

/+
TEST_OUTPUT:
---
fail_compilation/fail9665a.d(65): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(70): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(75): Error: immutable field 'v' initialized multiple times
---
+/
struct S1C
{
immutable int v;
Expand All @@ -77,6 +79,16 @@ struct S1C
/***************************************************/
// with control flow

/+
TEST_OUTPUT:
---
fail_compilation/fail9665a.d(98): Error: immutable field 'v' initialization is not allowed in loops or after labels
fail_compilation/fail9665a.d(103): Error: immutable field 'v' initialization is not allowed in loops or after labels
fail_compilation/fail9665a.d(108): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(113): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(118): Error: immutable field 'v' initialized multiple times
---
+/
struct S2
{
immutable int v;
Expand Down Expand Up @@ -110,6 +122,13 @@ struct S2
/***************************************************/
// with immutable constructor

/+
TEST_OUTPUT:
---
fail_compilation/fail9665a.d(139): Error: immutable field 'v' initialized multiple times
fail_compilation/fail9665a.d(143): Error: immutable field 'w' initialized multiple times
---
+/
struct S3
{
int v;
Expand All @@ -128,6 +147,12 @@ struct S3
/***************************************************/
// in __traits(compiles)

/+
TEST_OUTPUT:
---
fail_compilation/fail9665a.d(162): Error: immutable field 'v' initialized multiple times
---
+/
struct S4
{
immutable int v;
Expand Down
31 changes: 18 additions & 13 deletions test/fail_compilation/fail9665b.d
Expand Up @@ -11,19 +11,12 @@ struct X
/+
TEST_OUTPUT:
---
fail_compilation/fail9665b.d(39): Error: one path skips field x2
fail_compilation/fail9665b.d(40): Error: one path skips field x3
fail_compilation/fail9665b.d(42): Error: one path skips field x5
fail_compilation/fail9665b.d(43): Error: one path skips field x6
fail_compilation/fail9665b.d(37): Error: constructor fail9665b.S1.this field x1 must be initialized in constructor
fail_compilation/fail9665b.d(37): Error: constructor fail9665b.S1.this field x4 must be initialized in constructor
fail_compilation/fail9665b.d(60): Error: one path skips field x2
fail_compilation/fail9665b.d(61): Error: one path skips field x3
fail_compilation/fail9665b.d(63): Error: one path skips field x5
fail_compilation/fail9665b.d(64): Error: one path skips field x6
fail_compilation/fail9665b.d(58): Error: constructor fail9665b.S2!(X).S2.this field x1 must be initialized in constructor, because it is nested struct
fail_compilation/fail9665b.d(58): Error: constructor fail9665b.S2!(X).S2.this field x4 must be initialized in constructor, because it is nested struct
fail_compilation/fail9665b.d(71): Error: template instance fail9665b.S2!(X) error instantiating
fail_compilation/fail9665b.d(32): Error: one path skips field x2
fail_compilation/fail9665b.d(33): Error: one path skips field x3
fail_compilation/fail9665b.d(35): Error: one path skips field x5
fail_compilation/fail9665b.d(36): Error: one path skips field x6
fail_compilation/fail9665b.d(30): Error: field x1 must be initialized in constructor
fail_compilation/fail9665b.d(30): Error: field x4 must be initialized in constructor
---
+/
struct S1
Expand All @@ -47,6 +40,18 @@ struct S1
/***************************************************/
// with nested struct

/+
TEST_OUTPUT:
---
fail_compilation/fail9665b.d(65): Error: one path skips field x2
fail_compilation/fail9665b.d(66): Error: one path skips field x3
fail_compilation/fail9665b.d(68): Error: one path skips field x5
fail_compilation/fail9665b.d(69): Error: one path skips field x6
fail_compilation/fail9665b.d(63): Error: field x1 must be initialized in constructor, because it is nested struct
fail_compilation/fail9665b.d(63): Error: field x4 must be initialized in constructor, because it is nested struct
fail_compilation/fail9665b.d(76): Error: template instance fail9665b.S2!(X) error instantiating
---
+/
struct S2(X)
{
X x1;
Expand Down
22 changes: 12 additions & 10 deletions test/runnable/test28.d
Expand Up @@ -652,21 +652,23 @@ class Confectionary
{
this(int sugar)
{
//if (sugar < 500)
// tastiness = 200;
//if (sugar < 500)
// tastiness = 200;

//for (int i = 0; i < 10; ++i)
// tastiness = 300;
//for (int i = 0; i < 10; ++i)
// tastiness = 300;

//int[] tastinesses_array;
//int[] tastinesses_array;

//foreach (n; tastinesses_array)
// tastiness = n;
//foreach (n; tastinesses_array)
// tastiness = n;

int[int] tastinesses_aa;
//int[int] tastinesses_aa;

foreach (n; tastinesses_aa)
tastiness = n;
//foreach (n; tastinesses_aa)
// tastiness = n;

tastiness = 1;
}

const int tastiness;
Expand Down

0 comments on commit d1beeaa

Please sign in to comment.