Skip to content

Commit

Permalink
merge D2 pull #803 fix Issue 6681
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Mar 16, 2012
1 parent 136c107 commit f8fcbf1
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 23 deletions.
25 changes: 25 additions & 0 deletions src/declaration.c
Expand Up @@ -1290,6 +1290,31 @@ ExpInitializer *VarDeclaration::getExpInitializer()
void VarDeclaration::semantic2(Scope *sc)
{
//printf("VarDeclaration::semantic2('%s')\n", toChars());
// Inside unions, default to void initializers
if (!init && sc->inunion && !toParent()->isFuncDeclaration())
{
AggregateDeclaration *aad = parent->isAggregateDeclaration();
if (aad)
{
if (aad->fields[0] == this)
{
int hasinit = 0;
for (size_t i = 1; i < aad->fields.dim; i++)
{
if (aad->fields[i]->init &&
!aad->fields[i]->init->isVoidInitializer())
{
hasinit = 1;
break;
}
}
if (!hasinit)
init = new ExpInitializer(loc, type->defaultInitLiteral(loc));
}
else
init = new VoidInitializer(loc);
}
}
if (init && !toParent()->isFuncDeclaration())
{ inuse++;
#if 0
Expand Down
145 changes: 129 additions & 16 deletions src/interpret.c
Expand Up @@ -250,6 +250,16 @@ struct ClassReferenceExp : Expression
{
return value->sd->isClassDeclaration();
}
VarDeclaration *getFieldAt(int index)
{
ClassDeclaration *cd = originalClass();
size_t fieldsSoFar = 0;
while (index - fieldsSoFar >= cd->fields.dim)
{ fieldsSoFar += cd->fields.dim;
cd = cd->baseClass;
}
return cd->fields.tdata()[index - fieldsSoFar];
}
// Return index of the field, or -1 if not found
int getFieldIndex(Type *fieldtype, size_t fieldoffset)
{
Expand Down Expand Up @@ -290,6 +300,28 @@ struct ClassReferenceExp : Expression
}
};

struct VoidInitExp : Expression
{
VarDeclaration *var;

VoidInitExp(VarDeclaration *var, Type *type)
: Expression(var->loc, TOKvoid, sizeof(VoidInitExp))
{
this->var = var;
this->type = var->type;
}
char *toChars()
{
return (char *)"void";
}
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue)
{
error("CTFE internal error: trying to read uninitialized variable");
assert(0);
return EXP_CANT_INTERPRET;
}
};

// Return index of the field, or -1 if not found
// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v)
Expand Down Expand Up @@ -993,7 +1025,7 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2)
return Cat(type, e1, e2);
}

bool scrubArray(Loc loc, Expressions *elems);
bool scrubArray(Loc loc, Expressions *elems, bool structlit = false);

/* All results destined for use outside of CTFE need to have their CTFE-specific
* features removed.
Expand All @@ -1006,6 +1038,11 @@ Expression *scrubReturnValue(Loc loc, Expression *e)
error(loc, "%s class literals cannot be returned from CTFE", ((ClassReferenceExp*)e)->originalClass()->toChars());
return EXP_CANT_INTERPRET;
}
if (e->op == TOKvoid)
{
error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
e = new ErrorExp();
}
if (e->op == TOKslice)
{
e = resolveSlice(e);
Expand All @@ -1014,7 +1051,7 @@ Expression *scrubReturnValue(Loc loc, Expression *e)
{
StructLiteralExp *se = (StructLiteralExp *)e;
se->ownedByCtfe = false;
if (!scrubArray(loc, se->elements))
if (!scrubArray(loc, se->elements, true))
return EXP_CANT_INTERPRET;
}
if (e->op == TOKstring)
Expand All @@ -1040,14 +1077,17 @@ Expression *scrubReturnValue(Loc loc, Expression *e)
}

// Scrub all members of an array. Return false if error
bool scrubArray(Loc loc, Expressions *elems)
bool scrubArray(Loc loc, Expressions *elems, bool structlit)
{
for (size_t i = 0; i < elems->dim; i++)
{
Expression *m = elems->tdata()[i];
if (!m)
continue;
m = scrubReturnValue(loc, m);
if (m && m->op == TOKvoid && structlit)
m = NULL;
if (m)
m = scrubReturnValue(loc, m);
if (m == EXP_CANT_INTERPRET)
return false;
elems->tdata()[i] = m;
Expand Down Expand Up @@ -1939,11 +1979,16 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
{
if (v->init->isVoidInitializer())
{
error(loc, "variable %s is used before initialization", v->toChars());
return EXP_CANT_INTERPRET;
// var should have been initialized when it was created
error(loc, "CTFE internal error - trying to access uninitialized var");
assert(0);
e = EXP_CANT_INTERPRET;
}
else
{
e = v->init->toExpression();
e = e->interpret(istate);
}
e = v->init->toExpression();
e = e->interpret(istate);
}
else
e = v->type->defaultInitLiteral(loc);
Expand All @@ -1959,7 +2004,11 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
e = EXP_CANT_INTERPRET;
}
else if (!e)
error(loc, "variable %s is used before initialization", v->toChars());
{
assert(0);
assert(v->init && v->init->isVoidInitializer());
e = v->type->voidInitLiteral(v);
}
else if (exceptionOrCantInterpret(e))
return e;
else if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex)
Expand All @@ -1978,6 +2027,13 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
|| e->op == TOKassocarrayliteral || e->op == TOKslice
|| e->type->toBasetype()->ty == Tpointer)
return e; // it's already an Lvalue
else if (e->op == TOKvoid)
{
VoidInitExp *ve = (VoidInitExp *)e;
error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars());
errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars());
e = EXP_CANT_INTERPRET;
}
else
e = e->interpret(istate, goal);
}
Expand Down Expand Up @@ -2059,7 +2115,12 @@ Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal)
if (ie)
e = ie->exp->interpret(istate);
else if (v->init->isVoidInitializer())
e = NULL;
{
e = v->type->voidInitLiteral(v);
// There is no AssignExp for void initializers,
// so set it here.
v->setValue(e);
}
else
{
error("Declaration %s is not yet implemented in CTFE", toChars());
Expand Down Expand Up @@ -3158,7 +3219,7 @@ Expression *copyLiteral(Expression *e)
assert(v);
// If it is a void assignment, use the default initializer
if (!m)
m = v->type->defaultInitLiteral(e->loc);
m = v->type->voidInitLiteral(v);
if (m->op == TOKslice)
m = resolveSlice(m);
if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray)
Expand All @@ -3185,7 +3246,8 @@ Expression *copyLiteral(Expression *e)
|| e->op == TOKsymoff || e->op == TOKnull
|| e->op == TOKvar
|| e->op == TOKint64 || e->op == TOKfloat64
|| e->op == TOKchar || e->op == TOKcomplex80)
|| e->op == TOKchar || e->op == TOKcomplex80
|| e->op == TOKvoid)
{ // Simple value types
Expression *r = e->syntaxCopy();
r->type = e->type;
Expand Down Expand Up @@ -3355,7 +3417,7 @@ void assignInPlace(Expression *dest, Expression *src)
assert(o->op == e->op);
assignInPlace(o, e);
}
else if (e->type->ty == Tsarray && o->type->ty == Tsarray)
else if (e->type->ty == Tsarray && o->type->ty == Tsarray && e->op != TOKvoid)
{
assignInPlace(o, e);
}
Expand Down Expand Up @@ -3982,14 +4044,29 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
? (StructLiteralExp *)exx
: ((ClassReferenceExp *)exx)->value;
int fieldi = exx->op == TOKstructliteral
? se->getFieldIndex(member->type, member->offset)
: ((ClassReferenceExp *)exx)->getFieldIndex(member->type, member->offset);
? findFieldIndexByName(se->sd, member)
: ((ClassReferenceExp *)exx)->findFieldIndexByName(member);
if (fieldi == -1)
{
error("CTFE internal error: cannot find field %s in %s", member->toChars(), exx->toChars());
return EXP_CANT_INTERPRET;
}
assert(fieldi>=0 && fieldi < se->elements->dim);
assert(fieldi >= 0 && fieldi < se->elements->dim);
// If it's a union, set all other members of this union to void
if (exx->op == TOKstructliteral)
{
assert(se->sd);
int unionStart = se->sd->firstFieldInUnion(fieldi);
int unionSize = se->sd->numFieldsInUnion(fieldi);
for(int i = unionStart; i < unionStart + unionSize; ++i)
{ if (i == fieldi)
continue;
Expression **el = &se->elements->tdata()[i];
if ((*el)->op != TOKvoid)
*el = (*el)->type->voidInitLiteral(member);
}
}

if (newval->op == TOKstructliteral)
assignInPlace(se->elements->tdata()[fieldi], newval);
else
Expand Down Expand Up @@ -5817,6 +5894,13 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal)
if (e->op == TOKstructliteral || e->op == TOKarrayliteral ||
e->op == TOKassocarrayliteral || e->op == TOKstring)
return e;
if (e->op == TOKvoid)
{
VoidInitExp *ve = (VoidInitExp *)e;
error("cannot read uninitialized variable %s in ctfe", toChars());
ve->var->error("was uninitialized and used before set");
return EXP_CANT_INTERPRET;
}
if ( isPointer(type) )
{
return paintTypeOntoLiteral(type, e);
Expand Down Expand Up @@ -6495,6 +6579,10 @@ bool isCtfeValueValid(Expression *newval)
assert(((ArrayLiteralExp *)se->e1)->ownedByCtfe);
return true;
}
if (newval->op == TOKvoid)
{
return true;
}
newval->error("CTFE internal error: illegal value %s\n", newval->toChars());
return false;
}
Expand Down Expand Up @@ -6527,3 +6615,28 @@ void VarDeclaration::setValue(Expression *newval)
assert(isCtfeValueValid(newval));
ctfeStack.setValue(this, newval);
}


Expression *Type::voidInitLiteral(VarDeclaration *var)
{
return new VoidInitExp(var, this);
}

Expression *TypeSArray::voidInitLiteral(VarDeclaration *var)
{
return createBlockDuplicatedArrayLiteral(var->loc, this, next->voidInitLiteral(var), dim->toInteger());
}

Expression *TypeStruct::voidInitLiteral(VarDeclaration *var)
{
Expressions *exps = new Expressions();
exps->setDim(sym->fields.dim);
for (size_t i = 0; i < sym->fields.dim; i++)
{
(*exps)[i] = new VoidInitExp(var, sym->fields[i]->type);
}
StructLiteralExp *se = new StructLiteralExp(var->loc, sym, exps);
se->type = this;
se->ownedByCtfe = true;
return se;
}
3 changes: 3 additions & 0 deletions src/mtype.h
Expand Up @@ -237,6 +237,7 @@ struct Type : Object
virtual unsigned memalign(unsigned salign);
virtual Expression *defaultInit(Loc loc = 0);
virtual Expression *defaultInitLiteral(Loc loc);
virtual Expression *voidInitLiteral(VarDeclaration *var);
virtual int isZeroInit(Loc loc = 0); // if initializer is 0
virtual dt_t **toDt(dt_t **pdt);
Identifier *getTypeInfoIdent(int internal);
Expand Down Expand Up @@ -361,6 +362,7 @@ struct TypeSArray : TypeArray
MATCH implicitConvTo(Type *to);
Expression *defaultInit(Loc loc);
Expression *defaultInitLiteral(Loc loc);
Expression *voidInitLiteral(VarDeclaration *var);
dt_t **toDt(dt_t **pdt);
dt_t **toDtElem(dt_t **pdt, Expression *e);
MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes);
Expand Down Expand Up @@ -591,6 +593,7 @@ struct TypeStruct : Type
unsigned memalign(unsigned salign);
Expression *defaultInit(Loc loc);
Expression *defaultInitLiteral(Loc loc);
Expression *voidInitLiteral(VarDeclaration *var);
int isZeroInit(Loc loc);
int checkBoolean();
dt_t **toDt(dt_t **pdt);
Expand Down
3 changes: 2 additions & 1 deletion src/parse.c
@@ -1,6 +1,6 @@

// Compiler implementation of the D programming language
// Copyright (c) 1999-2011 by Digital Mars
// Copyright (c) 1999-2012 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
Expand Down Expand Up @@ -5560,6 +5560,7 @@ void initPrecedence()
precedence[TOKtraits] = PREC_primary;
precedence[TOKdefault] = PREC_primary;
precedence[TOKoverloadset] = PREC_primary;
precedence[TOKvoid] = PREC_primary;
#endif

// post
Expand Down
16 changes: 10 additions & 6 deletions src/todt.c
Expand Up @@ -109,7 +109,9 @@ dt_t *StructInitializer::toDt()
{ // An instance specific initializer was not provided.
// Look to see if there's a default initializer from the
// struct definition
if (v->init)
if (v->init && v->init->isVoidInitializer())
;
else if (v->init)
{
d = v->init->toDt();
}
Expand Down Expand Up @@ -842,7 +844,9 @@ void ClassDeclaration::toDt2(dt_t **pdt, ClassDeclaration *cd)
{ //printf("\t\t%s has initializer %s\n", v->toChars(), init->toChars());
ExpInitializer *ei = init->isExpInitializer();
Type *tb = v->type->toBasetype();
if (ei && tb->ty == Tsarray)
if (init->isVoidInitializer())
;
else if (ei && tb->ty == Tsarray)
((TypeSArray *)tb)->toDtElem(&dt, ei->exp);
else
dt = init->toDt();
Expand Down Expand Up @@ -910,16 +914,16 @@ void StructDeclaration::toDt(dt_t **pdt)
for (size_t i = 0; i < fields.dim; i++)
{
VarDeclaration *v = fields[i];
Initializer *init;

//printf("\tfield '%s' voffset %d, offset = %d\n", v->toChars(), v->offset, offset);
dt = NULL;
init = v->init;
Initializer *init = v->init;
if (init)
{ //printf("\t\thas initializer %s\n", init->toChars());
ExpInitializer *ei = init->isExpInitializer();
Type *tb = v->type->toBasetype();
if (ei && tb->ty == Tsarray)
if (init->isVoidInitializer())
;
else if (ei && tb->ty == Tsarray)
((TypeSArray *)tb)->toDtElem(&dt, ei->exp);
else
dt = init->toDt();
Expand Down

0 comments on commit f8fcbf1

Please sign in to comment.