forked from OSchip/llvm-project
Fix lifetime of conditional temporaries. Patch by Victor Zverovich!
llvm-svn: 89467
This commit is contained in:
parent
9c7efbb996
commit
0a66c26191
|
@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
|
||||||
|
|
||||||
// Check if temporaries need to be conditional. If so, we'll create a
|
// Check if temporaries need to be conditional. If so, we'll create a
|
||||||
// condition boolean, initialize it to 0 and
|
// condition boolean, initialize it to 0 and
|
||||||
if (!ConditionalTempDestructionStack.empty()) {
|
if (ConditionalBranchLevel != 0) {
|
||||||
CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
|
CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
|
||||||
|
|
||||||
// Initialize it to false. This initialization takes place right after
|
// Initialize it to false. This initialization takes place right after
|
||||||
|
@ -141,23 +141,3 @@ LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
|
||||||
|
|
||||||
return LV;
|
return LV;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CodeGenFunction::PushConditionalTempDestruction() {
|
|
||||||
// Store the current number of live temporaries.
|
|
||||||
ConditionalTempDestructionStack.push_back(LiveTemporaries.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGenFunction::PopConditionalTempDestruction() {
|
|
||||||
size_t NumLiveTemporaries = ConditionalTempDestructionStack.back();
|
|
||||||
ConditionalTempDestructionStack.pop_back();
|
|
||||||
|
|
||||||
// Pop temporaries.
|
|
||||||
while (LiveTemporaries.size() > NumLiveTemporaries) {
|
|
||||||
assert(LiveTemporaries.back().CondPtr &&
|
|
||||||
"Conditional temporary must have a cond ptr!");
|
|
||||||
|
|
||||||
PopCXXTemporary();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -389,21 +389,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
|
||||||
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
|
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
|
||||||
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
||||||
|
|
||||||
CGF.PushConditionalTempDestruction();
|
CGF.StartConditionalBranch();
|
||||||
CGF.EmitBlock(LHSBlock);
|
CGF.EmitBlock(LHSBlock);
|
||||||
|
|
||||||
// Handle the GNU extension for missing LHS.
|
// Handle the GNU extension for missing LHS.
|
||||||
assert(E->getLHS() && "Must have LHS for aggregate value");
|
assert(E->getLHS() && "Must have LHS for aggregate value");
|
||||||
|
|
||||||
Visit(E->getLHS());
|
Visit(E->getLHS());
|
||||||
CGF.PopConditionalTempDestruction();
|
CGF.FinishConditionalBranch();
|
||||||
CGF.EmitBranch(ContBlock);
|
CGF.EmitBranch(ContBlock);
|
||||||
|
|
||||||
CGF.PushConditionalTempDestruction();
|
CGF.StartConditionalBranch();
|
||||||
CGF.EmitBlock(RHSBlock);
|
CGF.EmitBlock(RHSBlock);
|
||||||
|
|
||||||
Visit(E->getRHS());
|
Visit(E->getRHS());
|
||||||
CGF.PopConditionalTempDestruction();
|
CGF.FinishConditionalBranch();
|
||||||
CGF.EmitBranch(ContBlock);
|
CGF.EmitBranch(ContBlock);
|
||||||
|
|
||||||
CGF.EmitBlock(ContBlock);
|
CGF.EmitBlock(ContBlock);
|
||||||
|
|
|
@ -1583,10 +1583,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
|
||||||
PI != PE; ++PI)
|
PI != PE; ++PI)
|
||||||
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
|
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
|
||||||
|
|
||||||
CGF.PushConditionalTempDestruction();
|
CGF.StartConditionalBranch();
|
||||||
CGF.EmitBlock(RHSBlock);
|
CGF.EmitBlock(RHSBlock);
|
||||||
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
||||||
CGF.PopConditionalTempDestruction();
|
CGF.FinishConditionalBranch();
|
||||||
|
|
||||||
// Reaquire the RHS block, as there may be subblocks inserted.
|
// Reaquire the RHS block, as there may be subblocks inserted.
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
RHSBlock = Builder.GetInsertBlock();
|
||||||
|
@ -1633,13 +1633,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
|
||||||
PI != PE; ++PI)
|
PI != PE; ++PI)
|
||||||
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
|
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
|
||||||
|
|
||||||
CGF.PushConditionalTempDestruction();
|
CGF.StartConditionalBranch();
|
||||||
|
|
||||||
// Emit the RHS condition as a bool value.
|
// Emit the RHS condition as a bool value.
|
||||||
CGF.EmitBlock(RHSBlock);
|
CGF.EmitBlock(RHSBlock);
|
||||||
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
||||||
|
|
||||||
CGF.PopConditionalTempDestruction();
|
CGF.FinishConditionalBranch();
|
||||||
|
|
||||||
// Reaquire the RHS block, as there may be subblocks inserted.
|
// Reaquire the RHS block, as there may be subblocks inserted.
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
RHSBlock = Builder.GetInsertBlock();
|
||||||
|
@ -1753,7 +1753,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
|
||||||
Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
|
Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGF.PushConditionalTempDestruction();
|
CGF.StartConditionalBranch();
|
||||||
CGF.EmitBlock(LHSBlock);
|
CGF.EmitBlock(LHSBlock);
|
||||||
|
|
||||||
// Handle the GNU extension for missing LHS.
|
// Handle the GNU extension for missing LHS.
|
||||||
|
@ -1763,15 +1763,15 @@ VisitConditionalOperator(const ConditionalOperator *E) {
|
||||||
else // Perform promotions, to handle cases like "short ?: int"
|
else // Perform promotions, to handle cases like "short ?: int"
|
||||||
LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
|
LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
|
||||||
|
|
||||||
CGF.PopConditionalTempDestruction();
|
CGF.FinishConditionalBranch();
|
||||||
LHSBlock = Builder.GetInsertBlock();
|
LHSBlock = Builder.GetInsertBlock();
|
||||||
CGF.EmitBranch(ContBlock);
|
CGF.EmitBranch(ContBlock);
|
||||||
|
|
||||||
CGF.PushConditionalTempDestruction();
|
CGF.StartConditionalBranch();
|
||||||
CGF.EmitBlock(RHSBlock);
|
CGF.EmitBlock(RHSBlock);
|
||||||
|
|
||||||
Value *RHS = Visit(E->getRHS());
|
Value *RHS = Visit(E->getRHS());
|
||||||
CGF.PopConditionalTempDestruction();
|
CGF.FinishConditionalBranch();
|
||||||
RHSBlock = Builder.GetInsertBlock();
|
RHSBlock = Builder.GetInsertBlock();
|
||||||
CGF.EmitBranch(ContBlock);
|
CGF.EmitBranch(ContBlock);
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
||||||
Builder(cgm.getModule().getContext()),
|
Builder(cgm.getModule().getContext()),
|
||||||
DebugInfo(0), IndirectBranch(0),
|
DebugInfo(0), IndirectBranch(0),
|
||||||
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
|
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
|
||||||
CXXThisDecl(0) {
|
CXXThisDecl(0),
|
||||||
|
ConditionalBranchLevel(0) {
|
||||||
LLVMIntTy = ConvertType(getContext().IntTy);
|
LLVMIntTy = ConvertType(getContext().IntTy);
|
||||||
LLVMPointerWidth = Target.getPointerWidth(0);
|
LLVMPointerWidth = Target.getPointerWidth(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,19 +176,23 @@ public:
|
||||||
/// this behavior for branches?
|
/// this behavior for branches?
|
||||||
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
|
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
|
||||||
|
|
||||||
/// PushConditionalTempDestruction - Should be called before a conditional
|
/// StartConditionalBranch - Should be called before a conditional part of an
|
||||||
/// part of an expression is emitted. For example, before the RHS of the
|
/// expression is emitted. For example, before the RHS of the expression below
|
||||||
/// expression below is emitted:
|
/// is emitted:
|
||||||
///
|
///
|
||||||
/// b && f(T());
|
/// b && f(T());
|
||||||
///
|
///
|
||||||
/// This is used to make sure that any temporaryes created in the conditional
|
/// This is used to make sure that any temporaries created in the conditional
|
||||||
/// branch are only destroyed if the branch is taken.
|
/// branch are only destroyed if the branch is taken.
|
||||||
void PushConditionalTempDestruction();
|
void StartConditionalBranch() {
|
||||||
|
++ConditionalBranchLevel;
|
||||||
|
}
|
||||||
|
|
||||||
/// PopConditionalTempDestruction - Should be called after a conditional
|
/// FinishConditionalBranch - Should be called after a conditional part of an
|
||||||
/// part of an expression has been emitted.
|
/// expression has been emitted.
|
||||||
void PopConditionalTempDestruction();
|
void FinishConditionalBranch() {
|
||||||
|
--ConditionalBranchLevel;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CGDebugInfo *DebugInfo;
|
CGDebugInfo *DebugInfo;
|
||||||
|
@ -298,10 +302,10 @@ private:
|
||||||
|
|
||||||
llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries;
|
llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries;
|
||||||
|
|
||||||
/// ConditionalTempDestructionStack - Contains the number of live temporaries
|
/// ConditionalBranchLevel - Contains the nesting level of the current
|
||||||
/// when PushConditionalTempDestruction was called. This is used so that
|
/// conditional branch. This is used so that we know if a temporary should be
|
||||||
/// we know how many temporaries were created by a certain expression.
|
/// destroyed conditionally.
|
||||||
llvm::SmallVector<size_t, 4> ConditionalTempDestructionStack;
|
unsigned ConditionalBranchLevel;
|
||||||
|
|
||||||
|
|
||||||
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
|
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
|
||||||
|
|
||||||
|
struct I {
|
||||||
|
int i;
|
||||||
|
I();
|
||||||
|
~I();
|
||||||
|
};
|
||||||
|
|
||||||
|
void g(int);
|
||||||
|
|
||||||
|
volatile int i;
|
||||||
|
|
||||||
|
void f1() {
|
||||||
|
// CHECK: call void @_ZN1IC1Ev
|
||||||
|
g(i ? I().i : 0);
|
||||||
|
// CHECK: call void @_Z1gi
|
||||||
|
// CHECK: call void @_ZN1ID1Ev
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN1IC1Ev
|
||||||
|
g(i || I().i);
|
||||||
|
// CHECK: call void @_Z1gi
|
||||||
|
// CHECK: call void @_ZN1ID1Ev
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN1IC1Ev
|
||||||
|
g(i && I().i);
|
||||||
|
// CHECK: call void @_Z1gi
|
||||||
|
// CHECK: call void @_ZN1ID1Ev
|
||||||
|
}
|
Loading…
Reference in New Issue