mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 19:06:02 +03:00
Don't destruct a temporary if its constructor throws.
This commit is contained in:
parent
b9c77c266a
commit
6fefec5a07
3 changed files with 48 additions and 2 deletions
41
gen/toir.cpp
41
gen/toir.cpp
|
@ -1146,8 +1146,47 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
if (result)
|
||||
return;
|
||||
|
||||
VarDeclarations& temporaries = gIR->func()->gen->getTemporariesToDestruct();
|
||||
|
||||
// check if we are about to construct a just declared temporary:
|
||||
// MyStruct(myArgs) => (MyStruct tmp; tmp).this(myArgs)
|
||||
bool constructingTemporary = false;
|
||||
if (!temporaries.empty() &&
|
||||
dfnval && dfnval->func && dfnval->func->isCtorDeclaration())
|
||||
{
|
||||
DotVarExp* dve = static_cast<DotVarExp*>(e->e1);
|
||||
if (dve->e1->op == TOKcomma)
|
||||
{
|
||||
CommaExp* ce = static_cast<CommaExp*>(dve->e1);
|
||||
if (ce->e1->op == TOKdeclaration && ce->e2->op == TOKvar)
|
||||
{
|
||||
VarExp* ve = static_cast<VarExp*>(ce->e2);
|
||||
if (temporaries.back()->equals(ve->var->isVarDeclaration()))
|
||||
constructingTemporary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// in that case, we have just pushed a new temporary due
|
||||
// to the DeclarationExp nested in e->e1, but we don't want it
|
||||
// to be destructed as long as it's not fully constructed yet;
|
||||
// i.e., don't destruct the temporary if its constructor throws
|
||||
// (DMD issue 13095)
|
||||
// => remember position in stack and pop temporarily
|
||||
int indexOfTemporary = (!constructingTemporary ? -1
|
||||
: static_cast<int>(temporaries.size()) - 1);
|
||||
VarDeclaration* temporary = (!constructingTemporary ? NULL
|
||||
: temporaries.pop());
|
||||
|
||||
result = DtoCallFunction(e->loc, e->type, fnval, e->arguments);
|
||||
|
||||
// insert the now fully constructed temporary at the original index;
|
||||
// i.e., before any new temporaries pushed by DtoCallFunction()
|
||||
if (constructingTemporary)
|
||||
temporaries.insert(indexOfTemporary, temporary);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -76,6 +76,11 @@ bool FuncGen::hasTemporariesToDestruct()
|
|||
return !temporariesToDestruct.empty();
|
||||
}
|
||||
|
||||
VarDeclarations& FuncGen::getTemporariesToDestruct()
|
||||
{
|
||||
return temporariesToDestruct;
|
||||
}
|
||||
|
||||
void FuncGen::destructTemporaries(unsigned numToKeep)
|
||||
{
|
||||
// pop one temporary after the other from the temporariesToDestruct stack
|
||||
|
|
|
@ -87,6 +87,8 @@ struct FuncGen
|
|||
|
||||
void pushTemporaryToDestruct(VarDeclaration* vd);
|
||||
bool hasTemporariesToDestruct();
|
||||
VarDeclarations& getTemporariesToDestruct();
|
||||
|
||||
void destructAllTemporariesAndRestoreStack();
|
||||
// pushes a landing pad which needs to be popped after the
|
||||
// following invoke instruction
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue