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

Fixed issue #426 — dtor / destructor not called for (rvalue) struct used in opApply #427

Merged
merged 5 commits into from
Jul 20, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -1055,7 +1055,7 @@ void DtoVarDeclaration(VarDeclaration* vd)
{
vd->ir.irLocal->value = val;
}
goto Lexit;
return;
}
}
}
Expand Down Expand Up @@ -1087,15 +1087,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