Skip to content

Commit

Permalink
Merge pull request #602 from donc/ctfe6933
Browse files Browse the repository at this point in the history
CTFE pointer and destructor bugs 6933 7185 7187 7194
  • Loading branch information
WalterBright committed Jan 3, 2012
2 parents 3a9dc09 + d24b65e commit ec7f241
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 58 deletions.
132 changes: 74 additions & 58 deletions src/interpret.c
Expand Up @@ -476,7 +476,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
if (thisarg->interpret(istate) == EXP_CANT_INTERPRET)
return EXP_CANT_INTERPRET;
}
static bool evaluatingArgs;
static int evaluatingArgs = 0;
if (arguments)
{
dim = arguments->dim;
Expand All @@ -500,9 +500,9 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
return EXP_CANT_INTERPRET;
}
// Convert all reference arguments into lvalue references
evaluatingArgs = true;
++evaluatingArgs;
earg = earg->interpret(istate, ctfeNeedLvalueRef);
evaluatingArgs = false;
--evaluatingArgs;
if (earg == EXP_CANT_INTERPRET)
return earg;
}
Expand All @@ -520,9 +520,9 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument
*/
earg = ((AddrExp *)earg)->e1;
}
evaluatingArgs = true;
++evaluatingArgs;
earg = earg->interpret(istate);
evaluatingArgs = false;
--evaluatingArgs;
if (earg == EXP_CANT_INTERPRET)
return earg;
}
Expand Down Expand Up @@ -1583,7 +1583,7 @@ Expression *FuncExp::interpret(InterState *istate, CtfeGoal goal)
* srcPointee is the genuine type (never void).
* destPointee may be void.
*/
bool isSafePointerCast(Type *srcPointee, Type*destPointee)
bool isSafePointerCast(Type *srcPointee, Type *destPointee)
{ // It's OK if both are the same (modulo const)
#if DMDV2
if (srcPointee->castMod(0) == destPointee->castMod(0))
Expand Down Expand Up @@ -1834,13 +1834,7 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal
else if (s)
{ // Struct static initializers, for example
if (s->dsym->toInitializer() == s->sym)
{ Expressions *exps = new Expressions();
e = new StructLiteralExp(loc, s->dsym, exps);
if (s->dsym->dtor)
{
error(loc, "CTFE fails for structs with destructors (Bugzilla 6933)");
return EXP_CANT_INTERPRET;
}
{ e = s->dsym->type->defaultInitLiteral();
e = e->semantic(NULL);
if (e->op == TOKerror)
e = EXP_CANT_INTERPRET;
Expand Down Expand Up @@ -2432,6 +2426,21 @@ Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs)
*ofs = 0;
if (e->op == TOKaddress)
e = ((AddrExp *)e)->e1;
if (e->op == TOKdotvar)
{
Expression *ex = ((DotVarExp *)e)->e1;
VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration();
assert(v);
StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex;
// We can't use getField, because it makes a copy
int i = -1;
if (ex->op == TOKclassreference)
i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset);
else
i = se->getFieldIndex(e->type, v->offset);
assert(i != -1);
e = se->elements->tdata()[i];
}
if (e->op == TOKindex)
{
IndexExp *ie = (IndexExp *)e;
Expand Down Expand Up @@ -2630,10 +2639,12 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex
dinteger_t ofs1, ofs2;
Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
// Note that type painting can occur with VarExp, so we
// must compare the variables being pointed to.
if (agg1 == agg2 ||
(agg1->op == TOKstring && agg2->op == TOKstring &&
((StringExp *)agg1)->string == ((StringExp *)agg2)->string))

(agg1->op == TOKvar && agg2->op == TOKvar &&
((VarExp *)agg1)->var == ((VarExp *)agg2)->var)
)
{
dinteger_t cm = ofs1 - ofs2;
dinteger_t n;
Expand All @@ -2654,11 +2665,11 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex
return new IntegerExp(loc, n, type);
}
int cmp;
if (e1->op == TOKnull)
if (agg1->op == TOKnull)
{
cmp = (e2->op == TOKnull);
cmp = (agg2->op == TOKnull);
}
else if (e2->op == TOKnull)
else if (agg2->op == TOKnull)
{
cmp = 0;
}
Expand Down Expand Up @@ -3549,27 +3560,53 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
Expressions *elements = new Expressions();
elements->setDim(newlen);
size_t copylen = oldlen < newlen ? oldlen : newlen;
if (oldlen !=0)
assert(oldval->op == TOKarrayliteral);
ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval;
for (size_t i = 0; i < copylen; i++)
elements->tdata()[i] = ae->elements->tdata()[i];
if (elemType->ty == Tstruct || elemType->ty == Tsarray)
{ /* If it is an aggregate literal representing a value type,
* we need to create a unique copy for each element
*/
for (size_t i = copylen; i < newlen; i++)
elements->tdata()[i] = copyLiteral(defaultElem);
if (oldval->op == TOKstring)
{
StringExp *oldse = (StringExp *)oldval;
unsigned char *s = (unsigned char *)mem.calloc(newlen + 1, oldse->sz);
memcpy(s, oldse->string, copylen * oldse->sz);
unsigned defaultValue = (unsigned)(defaultElem->toInteger());
for (size_t elemi = copylen; elemi < newlen; ++elemi)
{
switch (oldse->sz)
{
case 1: s[elemi] = defaultValue; break;
case 2: ((unsigned short *)s)[elemi] = defaultValue; break;
case 4: ((unsigned *)s)[elemi] = defaultValue; break;
default: assert(0);
}
}
StringExp *se = new StringExp(loc, s, newlen);
se->type = t;
se->sz = oldse->sz;
se->committed = oldse->committed;
se->ownedByCtfe = true;
newval = se;
}
else
{
for (size_t i = copylen; i < newlen; i++)
elements->tdata()[i] = defaultElem;
if (oldlen !=0)
assert(oldval->op == TOKarrayliteral);
ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval;
for (size_t i = 0; i < copylen; i++)
elements->tdata()[i] = ae->elements->tdata()[i];
if (elemType->ty == Tstruct || elemType->ty == Tsarray)
{ /* If it is an aggregate literal representing a value type,
* we need to create a unique copy for each element
*/
for (size_t i = copylen; i < newlen; i++)
elements->tdata()[i] = copyLiteral(defaultElem);
}
else
{
for (size_t i = copylen; i < newlen; i++)
elements->tdata()[i] = defaultElem;
}
ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements);
aae->type = t;
newval = aae;
aae->ownedByCtfe = true;
}
ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements);
aae->type = t;
newval = aae;
aae->ownedByCtfe = true;
// We have changed it into a reference assignment
// Note that returnValue is still the new length.
wantRef = true;
Expand Down Expand Up @@ -5381,28 +5418,7 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("AssertExp::interpret() %s\n", toChars());
#endif
if (this->e1->op == TOKthis)
{
if (istate->localThis)
{
if (istate->localThis->op == TOKdotvar
&& ((DotVarExp *)(istate->localThis))->e1->op == TOKthis)
return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var, ctfeNeedRvalue);
else
return istate->localThis->interpret(istate);
}
}
// Deal with pointers (including compiler-inserted assert(&this, "null this"))
if (this->e1->type->ty == Tpointer && this->e1->type->nextOf()->ty != Tfunction)
{
e1 = this->e1->interpret(istate, ctfeNeedLvalue);
if (exceptionOrCantInterpret(e1))
return e1;
if (e1->op != TOKnull)
return new IntegerExp(loc, 1, Type::tbool);
}
else
e1 = this->e1->interpret(istate);
e1 = this->e1->interpret(istate);
if (exceptionOrCantInterpret(e1))
return e1;
if (isTrueBool(e1))
Expand Down
66 changes: 66 additions & 0 deletions test/compilable/interpret3.d
Expand Up @@ -754,6 +754,22 @@ static assert(
return true;
}());

// 7185 char[].length = n

bool bug7185() {
auto arr = new char[2];
auto arr2 = new char[2];
arr2[] = "ab";
arr.length = 1;
arr2.length = 7;
assert(arr.length == 1);
assert(arr2.length == 7);
assert(arr2[0..2] == "ab");
return true;
}

static assert(bug7185());

/*******************************************
6934
*******************************************/
Expand Down Expand Up @@ -1944,6 +1960,37 @@ struct AList

static assert(AList.checkList()==2);

/**************************************************
7194 pointers as struct members
**************************************************/

struct S7194 { int* p, p2; }

int f7194() {
assert(S7194().p == null);
assert(!S7194().p);
assert(S7194().p == S7194().p2);
S7194 s = S7194();
assert(!s.p);
assert(s.p == null);
assert(s.p == s.p2);
int x;
s.p = &x;
s.p2 = s.p;
assert(s.p == &x);
return 0;
}

int g7194() {
auto s = S7194();
assert(s.p); // should fail
return 0;
}

static assert(f7194() == 0);
static assert(!is(typeof(compiles!( g7194() ))));


/**************************************************
4065 [CTFE] AA "in" operator doesn't work
**************************************************/
Expand Down Expand Up @@ -3801,6 +3848,7 @@ static assert(!S7165().f());
**************************************************/

int[] f7187() { return [0]; }
int[] f7187b(int n) { return [0]; }

int g7187(int[] r)
{
Expand All @@ -3809,3 +3857,21 @@ int g7187(int[] r)
}

static assert(g7187(f7187()));
static assert(g7187(f7187b(7)));

/**************************************************
6933 struct destructors
**************************************************/

struct Bug6933 {
int x = 3;
~this() { }
}

int test6933() {
Bug6933 q;
assert(q.x == 3);
return 3;
}

static assert(test6933());

0 comments on commit ec7f241

Please sign in to comment.