Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 7437,7980,8053 - Partial fix for stack overflow with recursive alias this #1028

Merged
merged 8 commits into from
Mar 7, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/cast.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2047,6 +2047,14 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression
assert(t1); assert(t1);
Type *t = t1; Type *t = t1;


/* The start type of alias this type recursion.
* In following case, we should save A, and stop recursion
* if it appears again.
* X -> Y -> [A] -> B -> A -> B -> ...
*/
Type *att1 = NULL;
Type *att2 = NULL;

//if (t1) printf("\tt1 = %s\n", t1->toChars()); //if (t1) printf("\tt1 = %s\n", t1->toChars());
//if (t2) printf("\tt2 = %s\n", t2->toChars()); //if (t2) printf("\tt2 = %s\n", t2->toChars());
#ifdef DEBUG #ifdef DEBUG
Expand Down Expand Up @@ -2350,12 +2358,22 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression
} }
else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis) else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
{ {
if (att1 && e1->type == att1)
goto Lincompatible;
if (!att1 && e1->type->checkAliasThisRec())
att1 = e1->type;
//printf("att tmerge(c || c) e1 = %s\n", e1->type->toChars());
e1 = resolveAliasThis(sc, e1); e1 = resolveAliasThis(sc, e1);
t1 = e1->type; t1 = e1->type;
continue; continue;
} }
else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis) else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
{ {
if (att2 && e2->type == att2)
goto Lincompatible;
if (!att2 && e2->type->checkAliasThisRec())
att2 = e2->type;
//printf("att tmerge(c || c) e2 = %s\n", e2->type->toChars());
e2 = resolveAliasThis(sc, e2); e2 = resolveAliasThis(sc, e2);
t2 = e2->type; t2 = e2->type;
continue; continue;
Expand Down Expand Up @@ -2391,11 +2409,21 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression
Expression *e2b = NULL; Expression *e2b = NULL;
if (ts2->sym->aliasthis) if (ts2->sym->aliasthis)
{ {
if (att2 && e2->type == att2)
goto Lincompatible;
if (!att2 && e2->type->checkAliasThisRec())
att2 = e2->type;
//printf("att tmerge(s && s) e2 = %s\n", e2->type->toChars());
e2b = resolveAliasThis(sc, e2); e2b = resolveAliasThis(sc, e2);
i1 = e2b->implicitConvTo(t1); i1 = e2b->implicitConvTo(t1);
} }
if (ts1->sym->aliasthis) if (ts1->sym->aliasthis)
{ {
if (att1 && e1->type == att1)
goto Lincompatible;
if (!att1 && e1->type->checkAliasThisRec())
att1 = e1->type;
//printf("att tmerge(s && s) e1 = %s\n", e1->type->toChars());
e1b = resolveAliasThis(sc, e1); e1b = resolveAliasThis(sc, e1);
i2 = e1b->implicitConvTo(t2); i2 = e1b->implicitConvTo(t2);
} }
Expand Down Expand Up @@ -2423,13 +2451,23 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression
{ {
if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis) if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
{ {
if (att1 && e1->type == att1)
goto Lincompatible;
if (!att1 && e1->type->checkAliasThisRec())
att1 = e1->type;
//printf("att tmerge(s || s) e1 = %s\n", e1->type->toChars());
e1 = resolveAliasThis(sc, e1); e1 = resolveAliasThis(sc, e1);
t1 = e1->type; t1 = e1->type;
t = t1; t = t1;
goto Lagain; goto Lagain;
} }
if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis) if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
{ {
if (att2 && e2->type == att2)
goto Lincompatible;
if (!att2 && e2->type->checkAliasThisRec())
att2 = e2->type;
//printf("att tmerge(s || s) e2 = %s\n", e2->type->toChars());
e2 = resolveAliasThis(sc, e2); e2 = resolveAliasThis(sc, e2);
t2 = e2->type; t2 = e2->type;
t = t2; t = t2;
Expand Down
85 changes: 53 additions & 32 deletions src/expression.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1949,8 +1949,12 @@ Expression *Expression::checkToBoolean(Scope *sc)
assert(type); assert(type);
#endif #endif


// Structs can be converted to bool using opCast(bool)() Expression *e = this;
Type *t = type;
Type *tb = type->toBasetype(); Type *tb = type->toBasetype();
Type *att = NULL;
Lagain:
// Structs can be converted to bool using opCast(bool)()
if (tb->ty == Tstruct) if (tb->ty == Tstruct)
{ AggregateDeclaration *ad = ((TypeStruct *)tb)->sym; { AggregateDeclaration *ad = ((TypeStruct *)tb)->sym;
/* Don't really need to check for opCast first, but by doing so we /* Don't really need to check for opCast first, but by doing so we
Expand All @@ -1959,26 +1963,29 @@ Expression *Expression::checkToBoolean(Scope *sc)
Dsymbol *fd = search_function(ad, Id::cast); Dsymbol *fd = search_function(ad, Id::cast);
if (fd) if (fd)
{ {
Expression *e = new CastExp(loc, this, Type::tbool); e = new CastExp(loc, e, Type::tbool);
e = e->semantic(sc); e = e->semantic(sc);
return e; return e;
} }


// Forward to aliasthis. // Forward to aliasthis.
if (ad->aliasthis) if (ad->aliasthis && tb != att)
{ {
Expression *e = resolveAliasThis(sc, this); if (!att && tb->checkAliasThisRec())
e = e->checkToBoolean(sc); att = tb;
return e; e = resolveAliasThis(sc, e);
t = e->type;
tb = e->type->toBasetype();
goto Lagain;
} }
} }


if (!type->checkBoolean()) if (!t->checkBoolean())
{ if (type->toBasetype() != Type::terror) { if (tb != Type::terror)
error("expression %s of type %s does not have a boolean value", toChars(), type->toChars()); error("expression %s of type %s does not have a boolean value", toChars(), t->toChars());
return new ErrorExp(); return new ErrorExp();
} }
return this; return e;
} }


/**************************** /****************************
Expand Down Expand Up @@ -6179,6 +6186,7 @@ UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1)
: Expression(loc, op, size) : Expression(loc, op, size)
{ {
this->e1 = e1; this->e1 = e1;
this->att1 = NULL;
} }


Expression *UnaExp::syntaxCopy() Expression *UnaExp::syntaxCopy()
Expand Down Expand Up @@ -6219,6 +6227,9 @@ BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2)
{ {
this->e1 = e1; this->e1 = e1;
this->e2 = e2; this->e2 = e2;

this->att1 = NULL;
this->att2 = NULL;
} }


Expression *BinExp::syntaxCopy() Expression *BinExp::syntaxCopy()
Expand Down Expand Up @@ -8062,8 +8073,10 @@ Expression *CallExp::semantic(Scope *sc)


if (e1->op != TOKtype) if (e1->op != TOKtype)
{ {
if (ad->aliasthis) if (ad->aliasthis && e1->type != att1)
{ {
if (!att1 && e1->type->checkAliasThisRec())
att1 = e1->type;
e1 = resolveAliasThis(sc, e1); e1 = resolveAliasThis(sc, e1);
goto Lagain; goto Lagain;
} }
Expand Down Expand Up @@ -9524,8 +9537,10 @@ Expression *SliceExp::semantic(Scope *sc)
e = e->semantic(sc); e = e->semantic(sc);
return e; return e;
} }
if (ad->aliasthis) if (ad->aliasthis && e1->type != att1)
{ {
if (!att1 && e1->type->checkAliasThisRec())
att1 = e1->type;
e1 = resolveAliasThis(sc, e1); e1 = resolveAliasThis(sc, e1);
goto Lagain; goto Lagain;
} }
Expand Down Expand Up @@ -10384,6 +10399,7 @@ Expression *AssignExp::semantic(Scope *sc)


ae->e1 = ae->e1->semantic(sc); ae->e1 = ae->e1->semantic(sc);
ae->e1 = resolveProperties(sc, ae->e1); ae->e1 = resolveProperties(sc, ae->e1);
Expression *e1 = ae->e1;
Type *t1 = ae->e1->type->toBasetype(); Type *t1 = ae->e1->type->toBasetype();
if (t1->ty == Tstruct) if (t1->ty == Tstruct)
{ {
Expand All @@ -10402,26 +10418,28 @@ Expression *AssignExp::semantic(Scope *sc)
Expressions *a = (Expressions *)ae->arguments->copy(); Expressions *a = (Expressions *)ae->arguments->copy();
a->insert(0, e2); a->insert(0, e2);


Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); Expression *e = new DotIdExp(loc, e1, Id::indexass);
e = new CallExp(loc, e, a); e = new CallExp(loc, e, a);
e = e->semantic(sc); e = e->semantic(sc);
return e; return e;
} }
} }


// No opIndexAssign found yet, but there might be an alias this to try. // No opIndexAssign found yet, but there might be an alias this to try.
if (ad && ad->aliasthis) if (ad && ad->aliasthis && t1 != att1)
{ Expression *e = resolveAliasThis(sc, ae->e1); {
Type *t = e->type->toBasetype(); if (!att1 && t1->checkAliasThisRec())

att1 = t1;
if (t->ty == Tstruct) e1 = resolveAliasThis(sc, e1);
t1 = e1->type->toBasetype();
if (t1->ty == Tstruct)
{ {
ad = ((TypeStruct *)t)->sym; ad = ((TypeStruct *)t1)->sym;
goto L1; goto L1;
} }
else if (t->ty == Tclass) else if (t1->ty == Tclass)
{ {
ad = ((TypeClass *)t)->sym; ad = ((TypeClass *)t1)->sym;
goto L1; goto L1;
} }
} }
Expand All @@ -10431,14 +10449,15 @@ Expression *AssignExp::semantic(Scope *sc)
* converted to a.opSlice() already. * converted to a.opSlice() already.
*/ */
if (e1->op == TOKslice) if (e1->op == TOKslice)
{ Type *t1; {
SliceExp *ae = (SliceExp *)e1; SliceExp *ae = (SliceExp *)e1;
AggregateDeclaration *ad = NULL; AggregateDeclaration *ad = NULL;
Identifier *id = Id::index; Identifier *id = Id::index;


ae->e1 = ae->e1->semantic(sc); ae->e1 = ae->e1->semantic(sc);
ae->e1 = resolveProperties(sc, ae->e1); ae->e1 = resolveProperties(sc, ae->e1);
t1 = ae->e1->type->toBasetype(); Expression *e1 = ae->e1;
Type *t1 = ae->e1->type->toBasetype();
if (t1->ty == Tstruct) if (t1->ty == Tstruct)
{ {
ad = ((TypeStruct *)t1)->sym; ad = ((TypeStruct *)t1)->sym;
Expand All @@ -10459,26 +10478,28 @@ Expression *AssignExp::semantic(Scope *sc)
{ a->push(ae->lwr); { a->push(ae->lwr);
a->push(ae->upr); a->push(ae->upr);
} }
Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); Expression *e = new DotIdExp(loc, e1, Id::sliceass);
e = new CallExp(loc, e, a); e = new CallExp(loc, e, a);
e = e->semantic(sc); e = e->semantic(sc);
return e; return e;
} }
} }


// No opSliceAssign found yet, but there might be an alias this to try. // No opSliceAssign found yet, but there might be an alias this to try.
if (ad && ad->aliasthis) if (ad && ad->aliasthis && t1 != att1)
{ Expression *e = resolveAliasThis(sc, ae->e1); {
Type *t = e->type->toBasetype(); if (!att1 && t1->checkAliasThisRec())

att1 = t1;
if (t->ty == Tstruct) e1 = resolveAliasThis(sc, e1);
t1 = e1->type->toBasetype();
if (t1->ty == Tstruct)
{ {
ad = ((TypeStruct *)t)->sym; ad = ((TypeStruct *)t1)->sym;
goto L2; goto L2;
} }
else if (t->ty == Tclass) else if (t1->ty == Tclass)
{ {
ad = ((TypeClass *)t)->sym; ad = ((TypeClass *)t1)->sym;
goto L2; goto L2;
} }
} }
Expand Down
4 changes: 4 additions & 0 deletions src/expression.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -769,6 +769,7 @@ struct IsExp : Expression
struct UnaExp : Expression struct UnaExp : Expression
{ {
Expression *e1; Expression *e1;
Type *att1; // Save alias this type to detect recursion


UnaExp(Loc loc, enum TOK op, int size, Expression *e1); UnaExp(Loc loc, enum TOK op, int size, Expression *e1);
Expression *syntaxCopy(); Expression *syntaxCopy();
Expand All @@ -792,6 +793,9 @@ struct BinExp : Expression
Expression *e1; Expression *e1;
Expression *e2; Expression *e2;


Type *att1; // Save alias this type to detect recursion
Type *att2; // Save alias this type to detect recursion
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really need to be for every expression?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Some expressions

  • FileExp, AssertExp, DelegateExp ... derived from UnaExp
  • IndexExp, RemoveExp ... derived from BinExp

might not need save starting of alias this recursion.
But other expressions always need to do.


BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2);
Expression *syntaxCopy(); Expression *syntaxCopy();
int apply(apply_fp_t fp, void *param); int apply(apply_fp_t fp, void *param);
Expand Down
Loading