mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 17:11:44 +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
43
gen/toir.cpp
43
gen/toir.cpp
|
@ -1146,8 +1146,47 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result)
|
if (result)
|
||||||
result = DtoCallFunction(e->loc, e->type, fnval, e->arguments);
|
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();
|
return !temporariesToDestruct.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VarDeclarations& FuncGen::getTemporariesToDestruct()
|
||||||
|
{
|
||||||
|
return temporariesToDestruct;
|
||||||
|
}
|
||||||
|
|
||||||
void FuncGen::destructTemporaries(unsigned numToKeep)
|
void FuncGen::destructTemporaries(unsigned numToKeep)
|
||||||
{
|
{
|
||||||
// pop one temporary after the other from the temporariesToDestruct stack
|
// pop one temporary after the other from the temporariesToDestruct stack
|
||||||
|
|
|
@ -87,6 +87,8 @@ struct FuncGen
|
||||||
|
|
||||||
void pushTemporaryToDestruct(VarDeclaration* vd);
|
void pushTemporaryToDestruct(VarDeclaration* vd);
|
||||||
bool hasTemporariesToDestruct();
|
bool hasTemporariesToDestruct();
|
||||||
|
VarDeclarations& getTemporariesToDestruct();
|
||||||
|
|
||||||
void destructAllTemporariesAndRestoreStack();
|
void destructAllTemporariesAndRestoreStack();
|
||||||
// pushes a landing pad which needs to be popped after the
|
// pushes a landing pad which needs to be popped after the
|
||||||
// following invoke instruction
|
// following invoke instruction
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue