Skip to content

Commit

Permalink
A bit tricky initialization for the nested struct fields.
Browse files Browse the repository at this point in the history
A nested struct field will be initialized by T.init instead of T(), before the constructor calling.
  • Loading branch information
9rnsr committed Nov 5, 2012
1 parent 704230b commit 523903b
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 5 deletions.
8 changes: 8 additions & 0 deletions src/dsymbol.c
Expand Up @@ -508,6 +508,14 @@ AggregateDeclaration *Dsymbol::isAggregateMember() // are we a member of an
return NULL;
}

AggregateDeclaration *Dsymbol::isAggregateMember2() // are we a member of an aggregate?
{
Dsymbol *parent = toParent2();
if (parent && parent->isAggregateDeclaration())
return (AggregateDeclaration *)parent;
return NULL;
}

ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class?
{
AggregateDeclaration *ad = isAggregateMember();
Expand Down
1 change: 1 addition & 0 deletions src/dsymbol.h
Expand Up @@ -174,6 +174,7 @@ struct Dsymbol : Object
virtual void defineRef(Dsymbol *s);
virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate?
AggregateDeclaration *isAggregateMember2(); // are we a member of an aggregate?
ClassDeclaration *isClassMember(); // are we a member of a class?
virtual int isExport(); // is Dsymbol exported?
virtual int isImportedSymbol(); // is Dsymbol imported?
Expand Down
19 changes: 17 additions & 2 deletions src/expression.c
Expand Up @@ -4014,6 +4014,7 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *
this->soffset = 0;
this->fillHoles = 1;
this->ownedByCtfe = false;
this->ctorinit = 0;
//printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
}

Expand Down Expand Up @@ -4115,6 +4116,8 @@ Expression *StructLiteralExp::semantic(Scope *sc)
}
}
}
else if (v->type->needsNested() && ctorinit)
e = v->type->defaultInit(loc);
else
e = v->type->defaultInitLiteral(loc);
offset = v->offset + v->type->size();
Expand Down Expand Up @@ -7882,7 +7885,17 @@ Expression *CallExp::semantic(Scope *sc)
{
// Create variable that will get constructed
Identifier *idtmp = Lexer::uniqueId("__ctmp");
VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL);

ExpInitializer *ei = NULL;
if (t1->needsNested())
{
Expressions *args = new Expressions();
StructLiteralExp *se = new StructLiteralExp(loc, (StructDeclaration *)ad, args);
se->ctorinit = 1;
ei = new ExpInitializer(loc, se);
}

VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, ei);
tmp->storage_class |= STCctfe;
Expression *av = new DeclarationExp(loc, tmp);
av = new CommaExp(loc, av, new VarExp(loc, tmp));
Expand Down Expand Up @@ -10538,6 +10551,8 @@ Expression *AssignExp::semantic(Scope *sc)
}
}

int ctorinit = e1->checkCtorInit(sc);

// Determine if this is an initialization of a reference
int refinit = 0;
if (op == TOKconstruct && e1->op == TOKvar)
Expand Down Expand Up @@ -10701,7 +10716,7 @@ Expression *AssignExp::semantic(Scope *sc)
else if (e1->op == TOKslice)
{
Type *tn = e1->type->nextOf();
if (op == TOKassign && !tn->isMutable() && !e1->checkCtorInit(sc))
if (op == TOKassign && !ctorinit && !tn->isMutable())
{ error("slice %s is not mutable", e1->toChars());
return new ErrorExp();
}
Expand Down
1 change: 1 addition & 0 deletions src/expression.h
Expand Up @@ -496,6 +496,7 @@ struct StructLiteralExp : Expression
size_t soffset; // offset from start of s
int fillHoles; // fill alignment 'holes' with zero
bool ownedByCtfe; // true = created in CTFE
int ctorinit;

StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL);

Expand Down
4 changes: 3 additions & 1 deletion src/func.c
Expand Up @@ -1156,7 +1156,7 @@ void FuncDeclaration::semantic3(Scope *sc)
sym->parent = sc2->scopesym;
sc2 = sc2->push(sym);

AggregateDeclaration *ad = isAggregateMember();
AggregateDeclaration *ad = isAggregateMember2();

/* If this is a class constructor
*/
Expand Down Expand Up @@ -1260,6 +1260,8 @@ void FuncDeclaration::semantic3(Scope *sc)
}
else if (v->storage_class & STCnodefaultctor)
error("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());
}
}
}
Expand Down
118 changes: 116 additions & 2 deletions test/runnable/nested.d
Expand Up @@ -1773,7 +1773,7 @@ template filter8339(alias pred)
auto filter8339(R)(R r) {
struct Result {
R range;
this(R r) {}
this(R r) { range = r; }
auto front() { return pred(0); }
}
return Result(r);
Expand All @@ -1784,7 +1784,7 @@ void test8339b()
static makefilter() { int n; return filter8339!(a=>n)([]); }

auto r1 = makefilter();
static assert(!is(typeof({ filter8339!(a=>a)(r1); })));
filter8339!(a=>a)(r1);
}

void test8339c()
Expand Down Expand Up @@ -1865,6 +1865,118 @@ void test8923a()
Z[1] z2c = Z(s1a);//z1c.s[0].foo(); // +/
}

struct Tuple8923(int v, T...)
{
T field;
static if (v == 1) this(T args) { } // should be an error
static if (v == 2) this(T args) { field = args; }
static if (v == 3) this(U...)(U args) { } // should be an error
static if (v == 4) this(U...)(U args) { field = args; }
//alias field this;
}
void test8923b()
{
int val;
struct S { void foo() { val = 1; } }

static assert(!__traits(compiles, Tuple8923!(1, S)(S()) ));
static assert(!__traits(compiles, Tuple8923!(3, S)(S()) ));

auto tup2 = Tuple8923!(2, S)(S());
tup2.field[0].foo(); // correctly initialized

auto tup4 = Tuple8923!(4, S)(S());
tup4.field[0].foo(); // correctly initialized
}

void test8392c()
{
int val;

struct S // is nested struct
{
void foo() { val = 1; } // access to val through the hidden frame pointer
}
S s1a; s1a.foo();
S s1b = S(); s1b.foo();
S[1] s2a; s2a[0].foo();
S[1] s2b = S(); s2b[0].foo();

// U,V,W,X are nested struct, but should work same as non-nested.
// 1: bare struct object. 2: static array of structs.
// a: default construction.
// b: construction by literal syntax which has no argument.
// c: construction by literal syntax which has one or more arguments.

struct U
{
S s;
void foo() { val = 2; }
}
U u1a; u1a.foo(); u1a.s.foo();
U u1b = U(); u1b.foo(); u1b.s.foo();
U u1c = U(s1a); u1c.foo(); u1c.s.foo();
U[1] u2a; u2a[0].foo(); u2a[0].s.foo();
U[1] u2b = U(); u2b[0].foo(); u2b[0].s.foo();
U[1] u2c = U(s1a); u2c[0].foo(); u2c[0].s.foo();

struct V
{
S[1] s;
void foo() { val = 2; }
}
V v1a; v1a.foo(); v1a.s[0].foo();
V v1b = V(); v1b.foo(); v1b.s[0].foo();
V v1c = V(s1a); v1c.foo(); v1c.s[0].foo();
V[1] v2a; v2a[0].foo(); v2a[0].s[0].foo();
V[1] v2b = V(); v2b[0].foo(); v2b[0].s[0].foo();
V[1] v2c = V(s1a); v2c[0].foo(); v2c[0].s[0].foo();

struct W
{
S s;
this(S s) { this.s = s; }
void foo() { val = 2; }
}
W w1a; w1a.foo(); w1a.s.foo();
W w1b = W(); w1b.foo(); w1b.s.foo();
W w1c = W(s1a); w1c.foo(); w1c.s.foo();
W[1] w2a; w2a[0].foo(); w2a[0].s.foo();
W[1] w2b = W(); w2b[0].foo(); w2b[0].s.foo();
W[1] w2c = W(s1a); w2c[0].foo(); w2c[0].s.foo();

struct X
{
S[1] s;
this(S s) { this.s[] = s; }
void foo() { val = 2; }
}
X x1a; x1a.foo(); x1a.s[0].foo();
X x1b = X(); x1b.foo(); x1b.s[0].foo();
X x1c = X(s1a); x1c.foo(); x1c.s[0].foo();
X[1] x2a; x2a[0].foo(); x2a[0].s[0].foo();
X[1] x2b = X(); x2b[0].foo(); x2b[0].s[0].foo();
X[1] x2c = X(s1a); x2c[0].foo(); x2c[0].s[0].foo();

// Both declarations, Y and Z should raise errors,
// because their ctors don't initialize their field 's'.
static assert(!__traits(compiles, {
struct Y1 { S s; this(S){} void foo() { val = 2; } }
}));
static assert(!__traits(compiles, {
struct Y2 { S s; this(T)(S){} void foo() { val = 2; } }
auto y2 = Y2!S(S()); // instantiate ctor
}));

static assert(!__traits(compiles, {
struct Z1 { S[1] s; this(S){} void foo() { val = 2; } }
}));
static assert(!__traits(compiles, {
struct Z2 { S[1] s; this(T)(S){} void foo() { val = 2; } }
auto z2 = Z2!S(S()); // instantiate ctor
}));
}

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

int main()
Expand Down Expand Up @@ -1938,6 +2050,8 @@ int main()
test8339b();
test8339c();
test8923a();
test8923b();
test8923c();

printf("Success\n");
return 0;
Expand Down

0 comments on commit 523903b

Please sign in to comment.