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
|
||||
// condition boolean, initialize it to 0 and
|
||||
if (!ConditionalTempDestructionStack.empty()) {
|
||||
if (ConditionalBranchLevel != 0) {
|
||||
CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
|
||||
|
||||
// Initialize it to false. This initialization takes place right after
|
||||
|
@ -141,23 +141,3 @@ LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
|
|||
|
||||
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());
|
||||
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
|
||||
|
||||
CGF.PushConditionalTempDestruction();
|
||||
CGF.StartConditionalBranch();
|
||||
CGF.EmitBlock(LHSBlock);
|
||||
|
||||
// Handle the GNU extension for missing LHS.
|
||||
assert(E->getLHS() && "Must have LHS for aggregate value");
|
||||
|
||||
Visit(E->getLHS());
|
||||
CGF.PopConditionalTempDestruction();
|
||||
CGF.FinishConditionalBranch();
|
||||
CGF.EmitBranch(ContBlock);
|
||||
|
||||
CGF.PushConditionalTempDestruction();
|
||||
CGF.StartConditionalBranch();
|
||||
CGF.EmitBlock(RHSBlock);
|
||||
|
||||
Visit(E->getRHS());
|
||||
CGF.PopConditionalTempDestruction();
|
||||
CGF.FinishConditionalBranch();
|
||||
CGF.EmitBranch(ContBlock);
|
||||
|
||||
CGF.EmitBlock(ContBlock);
|
||||
|
|
|
@ -1583,10 +1583,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
|
|||
PI != PE; ++PI)
|
||||
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
|
||||
|
||||
CGF.PushConditionalTempDestruction();
|
||||
CGF.StartConditionalBranch();
|
||||
CGF.EmitBlock(RHSBlock);
|
||||
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
||||
CGF.PopConditionalTempDestruction();
|
||||
CGF.FinishConditionalBranch();
|
||||
|
||||
// Reaquire the RHS block, as there may be subblocks inserted.
|
||||
RHSBlock = Builder.GetInsertBlock();
|
||||
|
@ -1633,13 +1633,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
|
|||
PI != PE; ++PI)
|
||||
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
|
||||
|
||||
CGF.PushConditionalTempDestruction();
|
||||
CGF.StartConditionalBranch();
|
||||
|
||||
// Emit the RHS condition as a bool value.
|
||||
CGF.EmitBlock(RHSBlock);
|
||||
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
|
||||
|
||||
CGF.PopConditionalTempDestruction();
|
||||
CGF.FinishConditionalBranch();
|
||||
|
||||
// Reaquire the RHS block, as there may be subblocks inserted.
|
||||
RHSBlock = Builder.GetInsertBlock();
|
||||
|
@ -1753,7 +1753,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
|
|||
Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
|
||||
}
|
||||
|
||||
CGF.PushConditionalTempDestruction();
|
||||
CGF.StartConditionalBranch();
|
||||
CGF.EmitBlock(LHSBlock);
|
||||
|
||||
// Handle the GNU extension for missing LHS.
|
||||
|
@ -1763,15 +1763,15 @@ VisitConditionalOperator(const ConditionalOperator *E) {
|
|||
else // Perform promotions, to handle cases like "short ?: int"
|
||||
LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
|
||||
|
||||
CGF.PopConditionalTempDestruction();
|
||||
CGF.FinishConditionalBranch();
|
||||
LHSBlock = Builder.GetInsertBlock();
|
||||
CGF.EmitBranch(ContBlock);
|
||||
|
||||
CGF.PushConditionalTempDestruction();
|
||||
CGF.StartConditionalBranch();
|
||||
CGF.EmitBlock(RHSBlock);
|
||||
|
||||
Value *RHS = Visit(E->getRHS());
|
||||
CGF.PopConditionalTempDestruction();
|
||||
CGF.FinishConditionalBranch();
|
||||
RHSBlock = Builder.GetInsertBlock();
|
||||
CGF.EmitBranch(ContBlock);
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
|||
Builder(cgm.getModule().getContext()),
|
||||
DebugInfo(0), IndirectBranch(0),
|
||||
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
|
||||
CXXThisDecl(0) {
|
||||
CXXThisDecl(0),
|
||||
ConditionalBranchLevel(0) {
|
||||
LLVMIntTy = ConvertType(getContext().IntTy);
|
||||
LLVMPointerWidth = Target.getPointerWidth(0);
|
||||
}
|
||||
|
|
|
@ -176,19 +176,23 @@ public:
|
|||
/// this behavior for branches?
|
||||
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
|
||||
|
||||
/// PushConditionalTempDestruction - Should be called before a conditional
|
||||
/// part of an expression is emitted. For example, before the RHS of the
|
||||
/// expression below is emitted:
|
||||
/// StartConditionalBranch - Should be called before a conditional part of an
|
||||
/// expression is emitted. For example, before the RHS of the expression below
|
||||
/// is emitted:
|
||||
///
|
||||
/// 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.
|
||||
void PushConditionalTempDestruction();
|
||||
void StartConditionalBranch() {
|
||||
++ConditionalBranchLevel;
|
||||
}
|
||||
|
||||
/// PopConditionalTempDestruction - Should be called after a conditional
|
||||
/// part of an expression has been emitted.
|
||||
void PopConditionalTempDestruction();
|
||||
/// FinishConditionalBranch - Should be called after a conditional part of an
|
||||
/// expression has been emitted.
|
||||
void FinishConditionalBranch() {
|
||||
--ConditionalBranchLevel;
|
||||
}
|
||||
|
||||
private:
|
||||
CGDebugInfo *DebugInfo;
|
||||
|
@ -298,10 +302,10 @@ private:
|
|||
|
||||
llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries;
|
||||
|
||||
/// ConditionalTempDestructionStack - Contains the number of live temporaries
|
||||
/// when PushConditionalTempDestruction was called. This is used so that
|
||||
/// we know how many temporaries were created by a certain expression.
|
||||
llvm::SmallVector<size_t, 4> ConditionalTempDestructionStack;
|
||||
/// ConditionalBranchLevel - Contains the nesting level of the current
|
||||
/// conditional branch. This is used so that we know if a temporary should be
|
||||
/// destroyed conditionally.
|
||||
unsigned ConditionalBranchLevel;
|
||||
|
||||
|
||||
/// 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