Skip to content

Commit

Permalink
Merge pull request #427 from AlexeyProkhin/issue426
Browse files Browse the repository at this point in the history
Fixed issue #426 — dtor / destructor not called for (rvalue) struct used in opApply
  • Loading branch information
redstar committed Jul 20, 2013
2 parents e5655c5 + 8b783da commit 795df4d
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 65 deletions.
4 changes: 0 additions & 4 deletions gen/irstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ struct IRScope
IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e);

const IRScope& operator=(const IRScope& rhs);

// list of variables needing destruction
std::vector<VarDeclaration*> varsInScope;
};

struct IRBuilderHelper
Expand Down Expand Up @@ -157,7 +154,6 @@ struct IRState
// basic block scopes
std::vector<IRScope> scopes;
IRScope& scope();
std::vector<VarDeclaration*> &varsInScope() { return scope().varsInScope; }
llvm::BasicBlock* scopebb();
llvm::BasicBlock* scopeend();
bool scopereturned();
Expand Down
11 changes: 1 addition & 10 deletions gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ void DtoVarDeclaration(VarDeclaration* vd)
{
vd->ir.irLocal->value = val;
}
goto Lexit;
return;
}
}
}
Expand Down Expand Up @@ -1105,15 +1105,6 @@ void DtoVarDeclaration(VarDeclaration* vd)
ex->exp->toElem(gIR);
}
}

Lexit:
/* Mark the point of construction of a variable that needs to be destructed.
*/
if (vd->edtor && !vd->noscope)
{
// Put vd on list of things needing destruction
gIR->varsInScope().push_back(vd);
}
}

DValue* DtoDeclarationExp(Dsymbol* declaration)
Expand Down
90 changes: 79 additions & 11 deletions gen/toir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "gen/warnings.h"
#include "ir/irtypeclass.h"
#include "ir/irtypestruct.h"
#include "ir/irlandingpad.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include <fstream>
Expand All @@ -64,23 +65,90 @@ void Expression::cacheLvalue(IRState* irs)
* Evaluate Expression, then call destructors on any temporaries in it.
*/

DValue *Expression::toElemDtor(IRState *irs)
DValue *Expression::toElemDtor(IRState *p)
{
Logger::println("Expression::toElemDtor(): %s", toChars());
LOG_SCOPE

size_t starti = irs->varsInScope().size();
DValue *val = toElem(irs);
size_t endi = irs->varsInScope().size();
class CallDestructors : public IRLandingPadCatchFinallyInfo {
public:
CallDestructors(const std::vector<Expression*> &edtors_)
: edtors(edtors_)
{}

// Add destructors
while (endi-- > starti)
{
VarDeclaration *vd = gIR->varsInScope().back();
gIR->varsInScope().pop_back();
vd->edtor->toElem(gIR);
const std::vector<Expression*> &edtors;

void toIR(LLValue */*eh_ptr*/ = 0)
{
std::vector<Expression*>::const_reverse_iterator itr, end = edtors.rend();
for (itr = edtors.rbegin(); itr != end; ++itr)
(*itr)->toElem(gIR);
}

static int searchVarsWithDesctructors(Expression *exp, void *edtors)
{
if (exp->op == TOKdeclaration) {
DeclarationExp *de = (DeclarationExp*)exp;
if (VarDeclaration *vd = de->declaration->isVarDeclaration()) {
while (vd->aliassym) {
vd = vd->aliassym->isVarDeclaration();
if (!vd)
return 0;
}

if (vd->init) {
if (ExpInitializer *ex = vd->init->isExpInitializer())
ex->exp->apply(&searchVarsWithDesctructors, edtors);
}

if (!vd->isDataseg() && vd->edtor && !vd->noscope)
static_cast<std::vector<Expression*>*>(edtors)->push_back(vd->edtor);
}
}
return 0;
}
};


// find destructors that must be called
std::vector<Expression*> edtors;
apply(&CallDestructors::searchVarsWithDesctructors, &edtors);

if (!edtors.empty()) {
if (op == TOKcall) {
// create finally block that calls destructors on temporaries
CallDestructors *callDestructors = new CallDestructors(edtors);

// create landing pad
llvm::BasicBlock *oldend = p->scopeend();
llvm::BasicBlock *landingpadbb = llvm::BasicBlock::Create(gIR->context(), "landingpad", p->topfunc(), oldend);

// set up the landing pad
IRLandingPad &pad = gIR->func()->gen->landingPadInfo;
pad.addFinally(callDestructors);
pad.push(landingpadbb);

// evaluate the expression
DValue *val = toElem(p);

// build the landing pad
llvm::BasicBlock *oldbb = p->scopebb();
pad.pop();

// call the destructors
gIR->scope() = IRScope(oldbb, oldend);
callDestructors->toIR();
delete callDestructors;
return val;
} else {
DValue *val = toElem(p);
CallDestructors(edtors).toIR();
return val;
}
}
return val;

return toElem(p);

}

//////////////////////////////////////////////////////////////////////////////////////////
Expand Down
93 changes: 58 additions & 35 deletions ir/irlandingpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@
#include "gen/tollvm.h"
#include "ir/irlandingpad.h"

// creates new landing pad
static llvm::LandingPadInst *createLandingPadInst()
{
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
LLType *retType = LLStructType::get(LLType::getInt8PtrTy(gIR->context()),
LLType::getInt32Ty(gIR->context()),
NULL);
return gIR->ir->CreateLandingPad(retType, personality_fn, 0, "landing_pad");
}

IRLandingPadCatchInfo::IRLandingPadCatchInfo(Catch* catchstmt_, llvm::BasicBlock* end_) :
catchStmt(catchstmt_), end(end_)
{
Expand Down Expand Up @@ -74,15 +84,54 @@ void IRLandingPadCatchInfo::toIR()
DtoDwarfBlockEnd();
}

IRLandingPadFinallyStatementInfo::IRLandingPadFinallyStatementInfo(Statement *finallyBody_) :
finallyBody(finallyBody_)
{
}

void IRLandingPadFinallyStatementInfo::toIR(LLValue *eh_ptr)
{
IRLandingPad &padInfo = gIR->func()->gen->landingPadInfo;
llvm::BasicBlock* &pad = gIR->func()->gen->landingPad;

// create collision landing pad that handles exceptions thrown inside the finally block
llvm::BasicBlock *collision = llvm::BasicBlock::Create(gIR->context(), "eh.collision", gIR->topfunc(), gIR->scopeend());
llvm::BasicBlock *bb = gIR->scopebb();
gIR->scope() = IRScope(collision, gIR->scopeend());
llvm::LandingPadInst *collisionLandingPad = createLandingPadInst();
LLValue* collision_eh_ptr = DtoExtractValue(collisionLandingPad, 0);
collisionLandingPad->setCleanup(true);
llvm::Function* collision_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_handle_collision");
gIR->CreateCallOrInvoke2(collision_fn, collision_eh_ptr, eh_ptr);
gIR->ir->CreateUnreachable();
gIR->scope() = IRScope(bb, gIR->scopeend());

// set collision landing pad as unwind target and emit the body of the finally
DtoDwarfBlockStart(finallyBody->loc);
padInfo.scopeStack.push(IRLandingPadScope(collision));
pad = collision;
finallyBody->toIR(gIR);
padInfo.scopeStack.pop();
pad = padInfo.get();
DtoDwarfBlockEnd();
}

void IRLandingPad::addCatch(Catch* catchstmt, llvm::BasicBlock* end)
{
unpushedScope.catches.push_back(IRLandingPadCatchInfo(catchstmt, end));
}

void IRLandingPad::addFinally(Statement* finallystmt)
void IRLandingPad::addFinally(Statement* finallyStmt)
{
assert(unpushedScope.finally == NULL && "only one finally per try-finally block");
unpushedScope.finally = new IRLandingPadFinallyStatementInfo(finallyStmt);
unpushedScope.isFinallyCreatedInternally = true;
}

void IRLandingPad::addFinally(IRLandingPadCatchFinallyInfo *finallyInfo)
{
assert(unpushedScope.finallyBody == NULL && "only one finally per try-finally block");
unpushedScope.finallyBody = finallystmt;
assert(unpushedScope.finally == NULL && "only one finally per try-finally block");
unpushedScope.finally = finallyInfo;
}

void IRLandingPad::push(llvm::BasicBlock* inBB)
Expand All @@ -103,6 +152,8 @@ void IRLandingPad::pop()
for (itr = scope.catches.begin(); itr != end; ++itr)
itr->toIR();
constructLandingPad(scope);
if (scope.finally && scope.isFinallyCreatedInternally)
delete scope.finally;
}

llvm::BasicBlock* IRLandingPad::get()
Expand All @@ -113,16 +164,6 @@ llvm::BasicBlock* IRLandingPad::get()
return scopeStack.top().target;
}

// creates new landing pad
static llvm::LandingPadInst *createLandingPadInst()
{
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
LLType *retType = LLStructType::get(LLType::getInt8PtrTy(gIR->context()),
LLType::getInt32Ty(gIR->context()),
NULL);
return gIR->ir->CreateLandingPad(retType, personality_fn, 0, "landing_pad");
}

void IRLandingPad::constructLandingPad(IRLandingPadScope scope)
{
// save and rewrite scope
Expand Down Expand Up @@ -152,6 +193,7 @@ void IRLandingPad::constructLandingPad(IRLandingPadScope scope)
gIR->ir->CreateStore(gIR->ir->CreateLoad(objectPtr), catch_var);
isFirstCatch = false;
}

// create next block
llvm::BasicBlock *next = llvm::BasicBlock::Create(gIR->context(), "eh.next", gIR->topfunc(), gIR->scopeend());
// get class info symbol
Expand All @@ -166,28 +208,9 @@ void IRLandingPad::constructLandingPad(IRLandingPadScope scope)
gIR->scope() = IRScope(next, gIR->scopeend());
}

if (scope.finallyBody) {
// create collision landing pad that handles exceptions thrown inside the finally block
llvm::BasicBlock *collision = llvm::BasicBlock::Create(gIR->context(), "eh.collision", gIR->topfunc(), gIR->scopeend());
llvm::BasicBlock *bb = gIR->scopebb();
gIR->scope() = IRScope(collision, gIR->scopeend());
llvm::LandingPadInst *collisionLandingPad = createLandingPadInst();
LLValue* collision_eh_ptr = DtoExtractValue(collisionLandingPad, 0);
collisionLandingPad->setCleanup(true);
llvm::Function* collision_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_handle_collision");
gIR->CreateCallOrInvoke2(collision_fn, collision_eh_ptr, eh_ptr);
gIR->ir->CreateUnreachable();
gIR->scope() = IRScope(bb, gIR->scopeend());

// set collision landing pad as unwind target and emit the body of the finally
DtoDwarfBlockStart(scope.finallyBody->loc);
scopeStack.push(IRLandingPadScope(collision));
gIR->func()->gen->landingPad = collision;
scope.finallyBody->toIR(gIR);
scopeStack.pop();
gIR->func()->gen->landingPad = get();
DtoDwarfBlockEnd();
landingPad->setCleanup(true);
if (scope.finally) {
scope.finally->toIR(eh_ptr);
landingPad->setCleanup(true);
}

if (scopeStack.empty())
Expand Down
32 changes: 28 additions & 4 deletions ir/irlandingpad.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,38 @@ struct IRLandingPadCatchInfo
ClassDeclaration *catchType;
};

// holds information about a single finally
class IRLandingPadCatchFinallyInfo
{
public:
virtual ~IRLandingPadCatchFinallyInfo() {}
virtual void toIR(LLValue *eh_ptr) = 0;
};

class IRLandingPadFinallyStatementInfo : public IRLandingPadCatchFinallyInfo
{
public:
IRLandingPadFinallyStatementInfo(Statement *finallyBody);
// codegen the finally block
void toIR(LLValue *eh_ptr);
private:
// the body of finally
Statement *finallyBody;
};

// holds information about a single try-catch-inally block
struct IRLandingPadScope
{
explicit IRLandingPadScope(llvm::BasicBlock *target_ = NULL) : target(target_), finallyBody(0) {}
explicit IRLandingPadScope(llvm::BasicBlock *target_ = NULL) :
target(target_), finally(0), isFinallyCreatedInternally(false) {}

// the target for invokes
llvm::BasicBlock *target;
// information about catch blocks
std::deque<IRLandingPadCatchInfo> catches;
// the body of finally
Statement *finallyBody;
// information about a finally block
IRLandingPadCatchFinallyInfo *finally;
bool isFinallyCreatedInternally;
};


Expand All @@ -73,8 +94,10 @@ struct IRLandingPad

// add catch information, will be used in next call to push
void addCatch(Catch* catchstmt, llvm::BasicBlock* end);
// add finally statement, will be used in next call to push
void addFinally(Statement* finallyStmt);
// add finally information, will be used in next call to push
void addFinally(Statement* finallystmt);
void addFinally(IRLandingPadCatchFinallyInfo *finallyInfo);

// builds the most recently constructed landing pad
// and the catch blocks, then pops the landing pad bb
Expand All @@ -85,6 +108,7 @@ struct IRLandingPad
llvm::Value* getExceptionStorage();

private:
friend class IRLandingPadFinallyStatementInfo;
// gets the current landing pad
llvm::BasicBlock* get();

Expand Down
2 changes: 1 addition & 1 deletion tests/d2/dmd-testsuite
Submodule dmd-testsuite updated 1 files
+61 −0 runnable/ldc_github_426.d

0 comments on commit 795df4d

Please sign in to comment.