Skip to content

Commit

Permalink
second stab at disabling default construction
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Aug 29, 2011
1 parent 8fa4a9e commit 1193f78
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 96 deletions.
51 changes: 15 additions & 36 deletions src/declaration.c
Expand Up @@ -83,6 +83,9 @@ enum PROT Declaration::prot()
*/

#if DMDV2

void modifyFieldVar(Scope *sc, VarDeclaration *var, Expression *e1);

void Declaration::checkModify(Loc loc, Scope *sc, Type *t)
{
if (sc->incontract && isParameter())
Expand All @@ -91,40 +94,10 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t)
if (sc->incontract && isResult())
error(loc, "cannot modify result '%s' in contract", toChars());

if (isCtorinit() && !t->isMutable())
if (isCtorinit() && !t->isMutable() ||
(storage_class & STCnodefaultctor))
{ // It's only modifiable if inside the right constructor
Dsymbol *s = sc->func;
while (1)
{
FuncDeclaration *fd = NULL;
if (s)
fd = s->isFuncDeclaration();
if (fd &&
((fd->isCtorDeclaration() && storage_class & STCfield) ||
(fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) &&
fd->toParent2() == toParent()
)
{
VarDeclaration *v = isVarDeclaration();
assert(v);
v->ctorinit = 1;
//printf("setting ctorinit\n");
}
else
{
if (s)
{ s = s->toParent2();
continue;
}
else
{
const char *p = isStatic() ? "static " : "";
error(loc, "can only initialize %sconst %s inside %sconstructor",
p, toChars(), p);
}
}
break;
}
modifyFieldVar(sc, isVarDeclaration(), NULL);
}
else
{
Expand Down Expand Up @@ -714,7 +687,7 @@ void VarDeclaration::semantic(Scope *sc)
printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars());
printf(" type = %s\n", type ? type->toChars() : "null");
printf(" stc = x%x\n", sc->stc);
printf(" storage_class = x%x\n", storage_class);
printf(" storage_class = x%llx\n", storage_class);
printf("linkage = %d\n", sc->linkage);
//if (strcmp(toChars(), "mul") == 0) halt();
#endif
Expand Down Expand Up @@ -1103,11 +1076,17 @@ void VarDeclaration::semantic(Scope *sc)
error("only fields, parameters or stack based variables can be inout");
}

if (!(storage_class & (STCfield | STCctfe)) && tb->ty == Tstruct &&
if (!(storage_class & (STCctfe | STCref)) && tb->ty == Tstruct &&
((TypeStruct *)tb)->sym->noDefaultCtor)
{
if (!init)
error("initializer required for type %s", type->toChars());
{ if (storage_class & STCfield)
/* For fields, we'll check the constructor later to make sure it is initialized
*/
storage_class |= STCnodefaultctor;
else
error("initializer required for type %s", type->toChars());
}
}
#endif

Expand Down
1 change: 1 addition & 0 deletions src/declaration.h
Expand Up @@ -82,6 +82,7 @@ enum PURE;
#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static
#define STCdisable 0x2000000000LL // for functions that are not callable
#define STCresult 0x4000000000LL // for result variables passed to out contracts
#define STCnodefaultctor 0x8000000000LL // must be set inside constructor

struct Match
{
Expand Down
12 changes: 9 additions & 3 deletions src/dsymbol.c
Expand Up @@ -440,14 +440,20 @@ AggregateDeclaration *Dsymbol::isThis()
return NULL;
}

ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class?
AggregateDeclaration *Dsymbol::isAggregateMember() // are we a member of an aggregate?
{
Dsymbol *parent = toParent();
if (parent && parent->isClassDeclaration())
return (ClassDeclaration *)parent;
if (parent && parent->isAggregateDeclaration())
return (AggregateDeclaration *)parent;
return NULL;
}

ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class?
{
AggregateDeclaration *ad = isAggregateMember();
return ad ? ad->isClassDeclaration() : NULL;
}

void Dsymbol::defineRef(Dsymbol *s)
{
assert(0);
Expand Down
3 changes: 2 additions & 1 deletion src/dsymbol.h
Expand Up @@ -163,7 +163,8 @@ struct Dsymbol : Object
virtual int isforwardRef();
virtual void defineRef(Dsymbol *s);
virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
virtual ClassDeclaration *isClassMember(); // are we a member of a class?
AggregateDeclaration *isAggregateMember(); // 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?
virtual int isDeprecated(); // is Dsymbol deprecated?
Expand Down
89 changes: 56 additions & 33 deletions src/expression.c
Expand Up @@ -6624,6 +6624,46 @@ Expression *DotVarExp::toLvalue(Scope *sc, Expression *e)
return this;
}

/***********************************************
* Mark variable v as modified if it is inside a constructor that var
* is a field in.
*/
void modifyFieldVar(Scope *sc, VarDeclaration *var, Expression *e1)
{
//printf("modifyFieldVar(var = %s)\n", var->toChars());
Dsymbol *s = sc->func;
while (1)
{
FuncDeclaration *fd = NULL;
if (s)
fd = s->isFuncDeclaration();
if (fd &&
((fd->isCtorDeclaration() && var->storage_class & STCfield) ||
(fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) &&
fd->toParent2() == var->toParent() &&
(!e1 || e1->op == TOKthis)
)
{
var->ctorinit = 1;
//printf("setting ctorinit\n");
}
else
{
if (s)
{ s = s->toParent2();
continue;
}
else if (var->storage_class & STCctorinit)
{
const char *p = var->isStatic() ? "static " : "";
error("can only initialize %sconst member %s inside %sconstructor",
p, var->toChars(), p);
}
}
break;
}
}

Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e)
{
#if 0
Expand All @@ -6643,45 +6683,17 @@ Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e)
{
if (var->isCtorinit())
{ // It's only modifiable if inside the right constructor
Dsymbol *s = sc->func;
while (1)
{
FuncDeclaration *fd = NULL;
if (s)
fd = s->isFuncDeclaration();
if (fd &&
((fd->isCtorDeclaration() && var->storage_class & STCfield) ||
(fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) &&
fd->toParent2() == var->toParent() &&
e1->op == TOKthis
)
{
VarDeclaration *v = var->isVarDeclaration();
assert(v);
v->ctorinit = 1;
//printf("setting ctorinit\n");
}
else
{
if (s)
{ s = s->toParent2();
continue;
}
else
{
const char *p = var->isStatic() ? "static " : "";
error("can only initialize %sconst member %s inside %sconstructor",
p, var->toChars(), p);
}
}
break;
}
modifyFieldVar(sc, var->isVarDeclaration(), e1);
}
else
{
error("cannot modify const/immutable/inout expression %s", toChars());
}
}
else if (var->storage_class & STCnodefaultctor)
{
modifyFieldVar(sc, var->isVarDeclaration(), e1);
}
return this;
}

Expand Down Expand Up @@ -9628,6 +9640,17 @@ Expression *AssignExp::semantic(Scope *sc)
StructDeclaration *sd = ((TypeStruct *)t1)->sym;
if (op == TOKassign)
{
/* See if we need to set ctorinit, i.e. track
* assignments to fields. An assignment to a field counts even
* if done through an opAssign overload.
*/
if (e1->op == TOKdotvar)
{ DotVarExp *dve = (DotVarExp *)e1;
VarDeclaration *v = dve->var->isVarDeclaration();
if (v && v->storage_class & STCnodefaultctor)
modifyFieldVar(sc, v, dve->e1);
}

Expression *e = op_overload(sc);
if (e && e1->op == TOKindex &&
((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
Expand Down
42 changes: 28 additions & 14 deletions src/func.c
Expand Up @@ -1254,14 +1254,14 @@ void FuncDeclaration::semantic3(Scope *sc)
sc2->incontract--;

if (fbody)
{ ClassDeclaration *cd = isClassMember();
{ AggregateDeclaration *ad = isAggregateMember();

/* If this is a class constructor
*/
if (isCtorDeclaration() && cd)
if (ad && isCtorDeclaration())
{
for (int i = 0; i < cd->fields.dim; i++)
{ VarDeclaration *v = cd->fields.tdata()[i];
for (size_t i = 0; i < ad->fields.dim; i++)
{ VarDeclaration *v = ad->fields[i];

v->ctorinit = 0;
}
Expand Down Expand Up @@ -1290,37 +1290,51 @@ void FuncDeclaration::semantic3(Scope *sc)
*/

Dsymbol *p = toParent();
ScopeDsymbol *ad = p->isScopeDsymbol();
if (!ad)
ScopeDsymbol *pd = p->isScopeDsymbol();
if (!pd)
{
error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars());
}
else
{
for (int i = 0; i < ad->members->dim; i++)
{ Dsymbol *s = ad->members->tdata()[i];
for (size_t i = 0; i < pd->members->dim; i++)
{ Dsymbol *s = pd->members->tdata()[i];

s->checkCtorConstInit();
}
}
}

if (isCtorDeclaration() && cd)
if (isCtorDeclaration() && ad)
{
//printf("callSuper = x%x\n", sc2->callSuper);

ClassDeclaration *cd = ad->isClassDeclaration();

// Verify that all the ctorinit fields got initialized
if (!(sc2->callSuper & CSXthis_ctor))
{
for (int i = 0; i < cd->fields.dim; i++)
{ VarDeclaration *v = cd->fields.tdata()[i];
for (size_t i = 0; i < ad->fields.dim; i++)
{ VarDeclaration *v = ad->fields[i];

if (v->ctorinit == 0 && v->isCtorinit() && !v->type->isMutable())
error("missing initializer for final field %s", v->toChars());
if (v->ctorinit == 0)
{
/* Current bugs in the flow analysis:
* 1. union members should not produce error messages even if
* not assigned to
* 2. structs should recognize delegating opAssign calls as well
* as delegating calls to other constructors
*/
if (v->isCtorinit() && !v->type->isMutable() && cd)
error("missing initializer for final field %s", v->toChars());
else if (v->storage_class & STCnodefaultctor)
error("field %s must be initialized in constructor", v->toChars());
}
}
}

if (!(sc2->callSuper & CSXany_ctor) &&
if (cd &&
!(sc2->callSuper & CSXany_ctor) &&
cd->baseClass && cd->baseClass->ctor)
{
sc2->callSuper = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/mars.c
Expand Up @@ -175,7 +175,7 @@ void verror(Loc loc, const char *format, va_list ap)
#endif
fprintf(stdmsg, "\n");
fflush(stdmsg);
//halt();
halt();
}
global.errors++;
}
Expand Down
1 change: 1 addition & 0 deletions src/parse.h
Expand Up @@ -111,6 +111,7 @@ struct Parser : Lexer
Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL, StorageClass storage_class = 0);
Dsymbols *parseDeclarations(StorageClass storage_class, unsigned char *comment);
void parseContracts(FuncDeclaration *f);
void checkDanglingElse(Loc elseloc);
Statement *parseStatement(int flags);
Initializer *parseInitializer();
Expression *parseDefaultInitExp();
Expand Down
16 changes: 8 additions & 8 deletions test/fail_compilation/fail6561.d
@@ -1,8 +1,8 @@
struct S
{
alias x this; // should cause undefined identifier error
}

void main()
{
}
struct S
{
alias x this; // should cause undefined identifier error
}

void main()
{
}

0 comments on commit 1193f78

Please sign in to comment.