Skip to content

Commit

Permalink
Fix Issue 12764 - Disabled struct default construction circumvented w…
Browse files Browse the repository at this point in the history
…hen field is written to
  • Loading branch information
RazvanN7 committed May 26, 2018
1 parent 97876ca commit 0e25d4d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
41 changes: 41 additions & 0 deletions src/dmd/expression.d
Expand Up @@ -5313,6 +5313,47 @@ extern (C++) final class DotVarExp : UnaExp
if (e1.op == TOK.this_)
return var.checkModify(loc, sc, e1, flag);

/* https://issues.dlang.org/show_bug.cgi?id=12764
* If inside a constructor and an expression of type `this.field.var`
* is encountered, where `field` is a struct declaration with
* default construction disabled, we must make sure that
* assigning to `var` does not imply that `field` was initialized
*/
if (sc.func)
{
auto ctd = sc.func.isCtorDeclaration();

// if inside a constructor scope and e1 of this DotVarExp
// is a DotVarExp, then check if e1.e1 is a `this` identifier
if (ctd && e1.op == TOK.dotVariable)
{
scope dve = cast(DotVarExp)e1;
if (dve.e1.op == TOK.this_)
{
scope v = dve.var.isVarDeclaration();
/* if v is a struct member field with no initializer, no default construction
* and v wasn't intialized before
*/
if (v && v.isField() && v.type.ty == Tstruct && !v._init && !v.ctorinit)
{
const sd = (cast(TypeStruct)v.type).sym;
if (sd.noDefaultCtor)
{
/* checkModify will consider that this is an initialization
* of v while it is actually an assignment of a field of v
*/
scope modifyLevel = v.checkModify(loc, sc, dve.e1, flag);
// reflect that assigning a field of v is not initialization of v
v.ctorinit = false;
if (modifyLevel == 2)
return 1;
return modifyLevel;
}
}
}
}
}

//printf("\te1 = %s\n", e1.toChars());
return e1.checkModifiable(sc, flag);
}
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/expressionsem.d
Expand Up @@ -6600,7 +6600,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (exp.op == TOK.assign && exp.e1.checkModifiable(sc) == 2)
{
//printf("[%s] change to init - %s\n", loc.toChars(), toChars());
//printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
exp.op = TOK.construct;

// https://issues.dlang.org/show_bug.cgi?id=13515
Expand Down
26 changes: 26 additions & 0 deletions test/fail_compilation/fail12764.d
@@ -0,0 +1,26 @@
// https://issues.dlang.org/show_bug.cgi?id=12764

/*
TEST_OUTPUT:
---
fail_compilation/fail12764.d(20): Error: field `s` must be initialized in constructor
---
*/

struct S
{
@disable this();

this(string) { }
int f;
}

class C
{
this(int)
{
s.f = 1; // circumvents default ctor!
}

S s;
}

0 comments on commit 0e25d4d

Please sign in to comment.