Skip to content

Commit

Permalink
more on destructors
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Mar 25, 2011
1 parent 085715a commit 9311001
Show file tree
Hide file tree
Showing 13 changed files with 226 additions and 31 deletions.
16 changes: 16 additions & 0 deletions src/declaration.c
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,8 @@ void VarDeclaration::semantic(Scope *sc)
Expression *e1 = new VarExp(loc, this);

Type *t = type->toBasetype();

Linit2:
if (t->ty == Tsarray && !(storage_class & (STCref | STCout)))
{
ei->exp = ei->exp->semantic(sc);
Expand Down Expand Up @@ -1174,6 +1176,15 @@ void VarDeclaration::semantic(Scope *sc)
}
}
}

/* Look for ((S tmp = S()),tmp) and replace it with just S()
*/
Expression *e2 = ei->exp->isTemp();
if (e2)
{
ei->exp = e2;
goto Linit2;
}
#endif
if (!ei->exp->implicitConvTo(type))
{
Expand Down Expand Up @@ -1351,6 +1362,11 @@ void VarDeclaration::semantic(Scope *sc)
if (edtor)
{
edtor = edtor->semantic(sc);

#if 0 // currently disabled because of std.stdio.stdin, stdout and stderr
if (isDataseg() && !(storage_class & STCextern))
error("static storage variables cannot have destructors");
#endif
}

sem = SemanticDone;
Expand Down
7 changes: 6 additions & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,12 @@ void DelegateExp::dump(int i)
void BinExp::dump(int i)
{
indent(i);
printf("%p %s type=%s e1=%p e2=%p\n", this, Token::toChars(op), type_print(type), e1, e2);
const char *sop = Token::toChars(op);
if (op == TOKblit)
sop = "blit";
else if (op == TOKconstruct)
sop = "construct";
printf("%p %s type=%s e1=%p e2=%p\n", this, sop, type_print(type), e1, e2);
if (e1)
e1->dump(i + 2);
if (e2)
Expand Down
74 changes: 66 additions & 8 deletions src/e2ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ elem *addressElem(elem *e, Type *t);
elem *array_toPtr(Type *t, elem *e);
elem *bit_assign(enum OPER op, elem *eb, elem *ei, elem *ev, int result);
elem *bit_read(elem *eb, elem *ei, int result);
elem *exp2_copytotemp(elem *e);
elem *appendDtors(IRState *irs, elem *er, size_t starti, size_t endi);

#define el_setLoc(e,loc) ((e)->Esrcpos.Sfilename = (char *)(loc).filename, \
(e)->Esrcpos.Slinnum = (loc).linnum)
Expand Down Expand Up @@ -1142,11 +1142,8 @@ elem *Dsymbol_toElem(Dsymbol *s, IRState *irs)
vd->toObjFile(0);
else
{
//printf("Dsymbol_toElem() %x\n", vd->storage_class);
sp = s->toSymbol();
//printf("test1 %d\n", cstate.CSpsymtab->top);
symbol_add(sp);
//printf("test2 %d\n", cstate.CSpsymtab->top);
//printf("\tadding symbol '%s'\n", sp->Sident);
if (vd->init)
{
Expand All @@ -1156,14 +1153,18 @@ elem *Dsymbol_toElem(Dsymbol *s, IRState *irs)
if (ie)
e = ie->exp->toElem(irs);
}
#if 1

/* Mark the point of construction of a variable that needs to be destructed.
*/
if (vd->edtor && !vd->noscope)
{
e = el_dctor(e, vd);

// Put vd on list of things needing destruction
if (!irs->varsInScope)
irs->varsInScope = new Array();
irs->varsInScope->push(vd);
}
#endif
}
}
else if ((cd = s->isClassDeclaration()) != NULL)
Expand Down Expand Up @@ -3217,7 +3218,21 @@ elem *XorAssignExp::toElem(IRState *irs)

elem *AndAndExp::toElem(IRState *irs)
{
elem *e = toElemBin(irs,OPandand);
tym_t tym = type->totym();

elem *el = e1->toElem(irs);

size_t starti = irs->varsInScope ? irs->varsInScope->dim : 0;
elem *er = e2->toElem(irs);
size_t endi = irs->varsInScope ? irs->varsInScope->dim : 0;

// Add destructors for e2
er = appendDtors(irs, er, starti, endi);

elem *e = el_bin(OPandand,tym,el,er);

el_setLoc(e,loc);

if (global.params.cov && e2->loc.linnum)
e->E2 = el_combine(incUsageElem(irs, e2->loc), e->E2);
return e;
Expand All @@ -3229,7 +3244,21 @@ elem *AndAndExp::toElem(IRState *irs)

elem *OrOrExp::toElem(IRState *irs)
{
elem *e = toElemBin(irs,OPoror);
tym_t tym = type->totym();

elem *el = e1->toElem(irs);

size_t starti = irs->varsInScope ? irs->varsInScope->dim : 0;
elem *er = e2->toElem(irs);
size_t endi = irs->varsInScope ? irs->varsInScope->dim : 0;

// Add destructors for e2
er = appendDtors(irs, er, starti, endi);

elem *e = el_bin(OPoror,tym,el,er);

el_setLoc(e,loc);

if (global.params.cov && e2->loc.linnum)
e->E2 = el_combine(incUsageElem(irs, e2->loc), e->E2);
return e;
Expand Down Expand Up @@ -5075,3 +5104,32 @@ elem *StructLiteralExp::toElem(IRState *irs)
el_setLoc(e,loc);
return e;
}

/********************************************
* Add destructors
*/

elem *appendDtors(IRState *irs, elem *er, size_t starti, size_t endi)
{
//printf("appendDtors(%d .. %d)\n", starti, endi);
elem *edtors = NULL;
for (size_t i = endi; i != starti;)
{
--i;
VarDeclaration *vd = (VarDeclaration *)irs->varsInScope->data[i];
if (vd)
{
//printf("appending dtor\n");
irs->varsInScope->data[i] = NULL;
elem *ed = vd->edtor->toElem(irs);
edtors = el_combine(edtors, ed);
}
}
if (edtors)
{
elem *e = el_same(&er);
er = el_combine(er, edtors);
er = el_combine(er, e);
}
return er;
}
42 changes: 28 additions & 14 deletions src/eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,19 @@
static char __file__[] = __FILE__; /* for tassert.h */
#include "tassert.h"

/* If we do our own EH tables and stack walking scheme
* (Otherwise use NT Structured Exception Handling)
*/
#define OUREH (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS)

/****************************
* Generate and output scope table.
*/

symbol *except_gentables()
{
//printf("except_gentables()\n");
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
#if OUREH

// BUG: alloca() changes the stack size, which is not reflected
// in the fixed eh tables.
Expand All @@ -61,6 +66,17 @@ symbol *except_gentables()
* Initializes the symbol s with the contents of the exception handler table.
*/

struct Guard
{
#if OUREH
unsigned offset; // offset of start of guarded section (Linux)
unsigned endoffset; // ending offset of guarded section (Linux)
#endif
int last_index; // previous index (enclosing guarded section)
unsigned catchoffset; // offset to catch block from symbol
void *finally; // finally code to execute
};

void except_fillInEHTable(symbol *s)
{
unsigned fsize = NPTRSIZE; // target size of function pointer
Expand All @@ -71,12 +87,7 @@ void except_fillInEHTable(symbol *s)
unsigned offset of ESP from EBP
unsigned offset from start of function to return code
unsigned nguards; // dimension of guard[] (Linux)
{ unsigned offset; // offset of start of guarded section (Linux)
unsigned endoffset; // ending offset of guarded section (Linux)
int last_index; // previous index (enclosing guarded section)
unsigned catchoffset; // offset to catch block from symbol
void *finally; // finally code to execute
} guard[];
Guard guard[];
catchoffset:
unsigned ncatches; // number of catch blocks
{ void *type; // symbol representing type
Expand All @@ -85,10 +96,13 @@ void except_fillInEHTable(symbol *s)
} catch[];
*/

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
#define GUARD_SIZE (I64 ? 3*8 : 5*4) // number of bytes in one guard
/* Be careful of this, as we need the sizeof Guard on the target, not
* in the compiler.
*/
#if OUREH
#define GUARD_SIZE (I64 ? 3*8 : 5*4) // sizeof(Guard)
#else
#define GUARD_SIZE (3*4)
#define GUARD_SIZE (sizeof(Guard))
#endif

int sz = 0;
Expand Down Expand Up @@ -119,7 +133,7 @@ void except_fillInEHTable(symbol *s)
// b->BC, b->Bscope_index, b->Blast_index, b->Boffset);
}

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
#if OUREH
pdt = dtsize_t(pdt,guarddim);
sz += NPTRSIZE;
#endif
Expand All @@ -143,7 +157,7 @@ void except_fillInEHTable(symbol *s)

int nsucc = list_nitems(b->Bsucc);

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
#if OUREH
//printf("DHandlerInfo: offset = %x", (int)(b->Boffset - startblock->Boffset));
pdt = dtdword(pdt,b->Boffset - startblock->Boffset); // offset to start of block

Expand Down Expand Up @@ -179,7 +193,7 @@ void except_fillInEHTable(symbol *s)
assert(bhandler->BC == BC_finally);
// To successor of BC_finally block
bhandler = list_block(bhandler->Bsucc);
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
#if OUREH
pdt = dtxoff(pdt,funcsym_p,bhandler->Boffset - startblock->Boffset, TYnptr); // finally handler address
#else
pdt = dtcoff(pdt,bhandler->Boffset); // finally handler address
Expand Down Expand Up @@ -211,7 +225,7 @@ void except_fillInEHTable(symbol *s)

pdt = dtsize_t(pdt,cod3_bpoffset(b->jcatchvar)); // EBP offset

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
#if OUREH
pdt = dtxoff(pdt,funcsym_p,bcatch->Boffset - startblock->Boffset, TYnptr); // catch handler address
#else
pdt = dtcoff(pdt,bcatch->Boffset); // catch handler address
Expand Down
59 changes: 59 additions & 0 deletions src/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,12 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
}
}

// Do not allow types that need destructors
if (arg->type->needsDestruction())
arg->error("cannot pass types that need destruction as variadic arguments");

// Convert static arrays to dynamic arrays
// BUG: I don't think this is right for D2
tb = arg->type->toBasetype();
if (tb->ty == Tsarray)
{ TypeSArray *ts = (TypeSArray *)tb;
Expand Down Expand Up @@ -1412,6 +1417,44 @@ Expressions *Expression::arraySyntaxCopy(Expressions *exps)
return a;
}

/***************************************************
* Recognize expressions of the form:
* ((T v = init), v)
* where v is a temp.
* This is used in optimizing out unnecessary temporary generation.
* Returns initializer expression of v if so, NULL if not.
*/

Expression *Expression::isTemp()
{
//printf("isTemp() %s\n", toChars());
if (op == TOKcomma)
{ CommaExp *ec = (CommaExp *)this;
if (ec->e1->op == TOKdeclaration &&
ec->e2->op == TOKvar)
{ DeclarationExp *de = (DeclarationExp *)ec->e1;
VarExp *ve = (VarExp *)ec->e2;
if (ve->var == de->declaration && ve->var->storage_class & STCctfe)
{ VarDeclaration *v = ve->var->isVarDeclaration();
if (v && v->init)
{
ExpInitializer *ei = v->init->isExpInitializer();
if (ei)
{ Expression *e = ei->exp;
if (e->op == TOKconstruct)
{ ConstructExp *ce = (ConstructExp *)e;
if (ce->e1->op == TOKvar && ((VarExp *)ce->e1)->var == ve->var)
e = ce->e2;
}
return e;
}
}
}
}
}
return NULL;
}

/******************************** IntegerExp **************************/

IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type)
Expand Down Expand Up @@ -3389,6 +3432,22 @@ Expression *StructLiteralExp::semantic(Scope *sc)
}

type = stype ? stype : sd->type;

/* If struct requires a destructor, rewrite as:
* (S tmp = S()),tmp
* so that the destructor can be hung on tmp.
*/
if (sd->dtor)
{
Identifier *idtmp = Lexer::uniqueId("__sl");
VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(0, this));
tmp->storage_class |= STCctfe;
Expression *ae = new DeclarationExp(loc, tmp);
Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp));
e = e->semantic(sc);
return e;
}

return this;
}

Expand Down
4 changes: 3 additions & 1 deletion src/expression.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

// Compiler implementation of the D programming language
// Copyright (c) 1999-2010 by Digital Mars
// Copyright (c) 1999-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
Expand Down Expand Up @@ -44,6 +44,7 @@ struct BinExp;
struct InterState;
struct Symbol; // back end symbol
struct OverloadSet;
struct Initializer;

enum TOK;

Expand Down Expand Up @@ -131,6 +132,7 @@ struct Expression : Object
Expression *addressOf(Scope *sc);
Expression *deref();
Expression *integralPromotions(Scope *sc);
Expression *isTemp();

Expression *toDelegate(Scope *sc, Type *t);
virtual void scanForNestedRef(Scope *sc);
Expand Down
2 changes: 1 addition & 1 deletion src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -3106,7 +3106,7 @@ Expression *AssertExp::interpret(InterState *istate)
if (ade->e1->op == TOKthis && istate->localThis)
if (istate->localThis->op == TOKdotvar
&& ((DotVarExp *)(istate->localThis))->e1->op == TOKthis)
return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var);
return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var);
else
return istate->localThis->interpret(istate);
}
Expand Down
Loading

0 comments on commit 9311001

Please sign in to comment.