Skip to content

Commit

Permalink
fix issue 6504, fix issue 7419
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Feb 4, 2012
1 parent 2014828 commit 467cf66
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 127 deletions.
132 changes: 85 additions & 47 deletions src/constfold.c
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,64 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
return e;
}

/* Set a slice of char array literal 'existingAE' from a string 'newval'.
* existingAE[firstIndex..firstIndex+newval.length] = newval.
*/
void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex)
{
size_t newlen = newval->len;
size_t sz = newval->sz;
unsigned char *s = (unsigned char *)newval->string;
Type *elemType = existingAE->type->nextOf();
for (size_t j = 0; j < newlen; j++)
{
dinteger_t val;
switch (sz)
{
case 1: val = s[j]; break;
case 2: val = ((unsigned short *)s)[j]; break;
case 4: val = ((unsigned *)s)[j]; break;
default:
assert(0);
break;
}
existingAE->elements->tdata()[j+firstIndex]
= new IntegerExp(newval->loc, val, elemType);
}
}

/* Set a slice of string 'existingSE' from a char array literal 'newae'.
* existingSE[firstIndex..firstIndex+newae.length] = newae.
*/
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
for (size_t j = 0; j < newae->elements->dim; j++)
{
unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger());
switch (existingSE->sz)
{
case 1: s[j+firstIndex] = value; break;
case 2: ((unsigned short *)s)[j+firstIndex] = value; break;
case 4: ((unsigned *)s)[j+firstIndex] = value; break;
default:
assert(0);
break;
}
}
}

/* Set a slice of string 'existingSE' from a string 'newstr'.
* existingSE[firstIndex..firstIndex+newstr.length] = newstr.
*/
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
size_t sz = existingSE->sz;
assert(sz == newstr->sz);
memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len);
}

/* Also return EXP_CANT_INTERPRET if this fails
*/
Expression *Cat(Type *type, Expression *e1, Expression *e2)
Expand Down Expand Up @@ -1460,62 +1518,42 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2)
else if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
t1->nextOf()->isintegral())
{
// Concatenate the strings
StringExp *es1 = (StringExp *)e2;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + i * sz, &v, sz);
// [chars] ~ string --> [chars]
StringExp *es = (StringExp *)e2;
ArrayLiteralExp *ea = (ArrayLiteralExp *)e1;
size_t len = es->len + ea->elements->dim;
Expressions * elems = new Expressions;
elems->setDim(len);
for (size_t i= 0; i < ea->elements->dim; ++i)
{
elems->tdata()[i] = ea->elements->tdata()[i];
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0;
es->type = type;
e = es;
ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems);
dest->type = type;
sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim);
return dest;
}
else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
t2->nextOf()->isintegral())
{
// Concatenate the strings
StringExp *es1 = (StringExp *)e1;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy(s, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz);
// string ~ [chars] --> [chars]
StringExp *es = (StringExp *)e1;
ArrayLiteralExp *ea = (ArrayLiteralExp *)e2;
size_t len = es->len + ea->elements->dim;
Expressions * elems = new Expressions;
elems->setDim(len);
for (size_t i= 0; i < ea->elements->dim; ++i)
{
elems->tdata()[es->len + i] = ea->elements->tdata()[i];
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0; //es1->committed;
es->type = type;
e = es;
ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems);
dest->type = type;
sliceAssignArrayLiteralFromString(dest, es, 0);
return dest;
}
else if (e1->op == TOKstring && e2->op == TOKint64)
{
// Concatenate the strings
// string ~ char --> string
void *s;
StringExp *es1 = (StringExp *)e1;
StringExp *es;
Expand Down
7 changes: 7 additions & 0 deletions src/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -1582,4 +1582,11 @@ Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2);

Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr);

// Const-folding functions used by CTFE

void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex);
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex);
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex);


#endif /* DMD_EXPRESSION_H */
161 changes: 81 additions & 80 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,73 @@ Expression *ctfeEqual(enum TOK op, Type *type, Expression *e1, Expression *e2)
return Equal(op, type, e1, e2);
}

Expression *ctfeCat(Type *type, Expression *e1, Expression *e2)
{
Loc loc = e1->loc;
Type *t1 = e1->type->toBasetype();
Type *t2 = e2->type->toBasetype();
Expression *e;
if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
t1->nextOf()->isintegral())
{
// [chars] ~ string => string (only valid for CTFE)
StringExp *es1 = (StringExp *)e2;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + i * sz, &v, sz);
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0;
es->type = type;
e = es;
return e;
}
else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
t2->nextOf()->isintegral())
{
// string ~ [chars] => string (only valid for CTFE)
// Concatenate the strings
StringExp *es1 = (StringExp *)e1;
ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
size_t len = es1->len + es2->elements->dim;
int sz = es1->sz;

void *s = mem.malloc((len + 1) * sz);
memcpy(s, es1->string, es1->len * sz);
for (size_t i = 0; i < es2->elements->dim; i++)
{ Expression *es2e = es2->elements->tdata()[i];
if (es2e->op != TOKint64)
return EXP_CANT_INTERPRET;
dinteger_t v = es2e->toInteger();
memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz);
}

// Add terminating 0
memset((unsigned char *)s + len * sz, 0, sz);

StringExp *es = new StringExp(loc, s, len);
es->sz = sz;
es->committed = 0; //es1->committed;
es->type = type;
e = es;
return e;
}
return Cat(type, e1, e2);
}

void scrubArray(Loc loc, Expressions *elems);

Expand Down Expand Up @@ -3213,66 +3280,6 @@ Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e)
return r;
}


/* Set a slice of char array literal 'existingAE' from a string 'newval'.
* existingAE[firstIndex..firstIndex+newval.length] = newval.
*/
void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex)
{
size_t newlen = newval->len;
size_t sz = newval->sz;
unsigned char *s = (unsigned char *)newval->string;
Type *elemType = existingAE->type->nextOf();
for (size_t j = 0; j < newlen; j++)
{
dinteger_t val;
switch (sz)
{
case 1: val = s[j]; break;
case 2: val = ((unsigned short *)s)[j]; break;
case 4: val = ((unsigned *)s)[j]; break;
default:
assert(0);
break;
}
existingAE->elements->tdata()[j+firstIndex]
= new IntegerExp(newval->loc, val, elemType);
}
}

/* Set a slice of string 'existingSE' from a char array literal 'newae'.
* existingSE[firstIndex..firstIndex+newae.length] = newae.
*/
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
for (size_t j = 0; j < newae->elements->dim; j++)
{
unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger());
switch (existingSE->sz)
{
case 1: s[j+firstIndex] = value; break;
case 2: ((unsigned short *)s)[j+firstIndex] = value; break;
case 4: ((unsigned *)s)[j+firstIndex] = value; break;
default:
assert(0);
break;
}
}
}

/* Set a slice of string 'existingSE' from a string 'newstr'.
* existingSE[firstIndex..firstIndex+newstr.length] = newstr.
*/
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex)
{
unsigned char *s = (unsigned char *)existingSE->string;
size_t sz = existingSE->sz;
assert(sz == newstr->sz);
memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len);
}


/* Set dest = src, where both dest and src are container value literals
* (ie, struct literals, or static arrays (can be an array literal or a string)
* Assignment is recursively in-place.
Expand Down Expand Up @@ -3448,6 +3455,13 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
{
wantRef = true;
}
// If it is a construction of a ref variable, it is a ref assignment
if (op == TOKconstruct && this->e1->op==TOKvar
&& ((VarExp*)this->e1)->var->storage_class & STCref)
{
wantRef = true;
}

if (fp)
{
while (e1->op == TOKcast)
Expand Down Expand Up @@ -3714,20 +3728,6 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
return EXP_CANT_INTERPRET;
}

// This happens inside compiler-generated foreach statements.
if (op==TOKconstruct && this->e1->op==TOKvar &&
this->e2->op == TOKindex
&& ((VarExp*)this->e1)->var->storage_class & STCref)
{
VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
#if (LOGASSIGN)
printf("FOREACH ASSIGN %s=%s\n", v->toChars(), e2->toChars());
#endif
v->setValueNull();
v->setValue(e2);
return e2;
}

e1 = resolveReferences(e1, istate->localThis);

// Unless we have a simple var assignment, we're
Expand Down Expand Up @@ -4432,15 +4432,17 @@ Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal)
return interpretAssignCommon(istate, goal, NULL);
}

#define BIN_ASSIGN_INTERPRET(op) \
#define BIN_ASSIGN_INTERPRET_CTFE(op, ctfeOp) \
Expression *op##AssignExp::interpret(InterState *istate, CtfeGoal goal) \
{ \
return interpretAssignCommon(istate, goal, &op); \
return interpretAssignCommon(istate, goal, &ctfeOp); \
}

#define BIN_ASSIGN_INTERPRET(op) BIN_ASSIGN_INTERPRET_CTFE(op, op)

BIN_ASSIGN_INTERPRET(Add)
BIN_ASSIGN_INTERPRET(Min)
BIN_ASSIGN_INTERPRET(Cat)
BIN_ASSIGN_INTERPRET_CTFE(Cat, ctfeCat)
BIN_ASSIGN_INTERPRET(Mul)
BIN_ASSIGN_INTERPRET(Div)
BIN_ASSIGN_INTERPRET(Mod)
Expand Down Expand Up @@ -4784,8 +4786,7 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal)
{
if (e->op == TOKslice)
e= resolveSlice(e);
e = expType(type, e);
e = copyLiteral(e);
e = paintTypeOntoLiteral(type, copyLiteral(e));
}
return e;
}
Expand Down Expand Up @@ -5314,7 +5315,7 @@ Expression *CatExp::interpret(InterState *istate, CtfeGoal goal)
return e2;
if (e2->op == TOKslice)
e2 = resolveSlice(e2);
e = Cat(type, e1, e2);
e = ctfeCat(type, e1, e2);
if (e == EXP_CANT_INTERPRET)
error("%s cannot be interpreted at compile time", toChars());
// We know we still own it, because we interpreted both e1 and e2
Expand Down

0 comments on commit 467cf66

Please sign in to comment.