mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-13 03:13:13 +01:00
Merge pull request #427 from AlexeyProkhin/issue426
Fixed issue #426 — dtor / destructor not called for (rvalue) struct used in opApply
This commit is contained in:
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -1073,7 +1073,7 @@ void DtoVarDeclaration(VarDeclaration* vd)
|
||||
{
|
||||
vd->ir.irLocal->value = val;
|
||||
}
|
||||
goto Lexit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
90
gen/toir.cpp
90
gen/toir.cpp
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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_)
|
||||
{
|
||||
@@ -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.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 = new IRLandingPadFinallyStatementInfo(finallyStmt);
|
||||
unpushedScope.isFinallyCreatedInternally = true;
|
||||
}
|
||||
|
||||
void IRLandingPad::addFinally(IRLandingPadCatchFinallyInfo *finallyInfo)
|
||||
{
|
||||
assert(unpushedScope.finally == NULL && "only one finally per try-finally block");
|
||||
unpushedScope.finally = finallyInfo;
|
||||
}
|
||||
|
||||
void IRLandingPad::push(llvm::BasicBlock* inBB)
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -85,6 +108,7 @@ struct IRLandingPad
|
||||
llvm::Value* getExceptionStorage();
|
||||
|
||||
private:
|
||||
friend class IRLandingPadFinallyStatementInfo;
|
||||
// gets the current landing pad
|
||||
llvm::BasicBlock* get();
|
||||
|
||||
|
||||
Submodule tests/d2/dmd-testsuite updated: 0510d182bf...e8c14b05ca
Reference in New Issue
Block a user