diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-06-12 20:42:33 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-06-12 20:42:33 +0000 |
commit | 736a947bdca65e9bcc1550772fd2120a1bcd47a8 (patch) | |
tree | ea96de43a836bdc53eed5f6eee4f77be747eb0e0 /clang/lib/CodeGen/CodeGenFunction.h | |
parent | 4fcb8c260eb0976496e931ee091462b527fc1971 (diff) | |
download | llvm-736a947bdca65e9bcc1550772fd2120a1bcd47a8.zip llvm-736a947bdca65e9bcc1550772fd2120a1bcd47a8.tar.gz llvm-736a947bdca65e9bcc1550772fd2120a1bcd47a8.tar.bz2 |
Reapply r183721, reverted in r183776, with a fix for a bug in the former (we
were lacking ExprWithCleanups nodes in some cases where the new approach to
lifetime extension needed them).
Original commit message:
Rework IR emission for lifetime-extended temporaries. Instead of trying to walk
into the expression and dig out a single lifetime-extended entity and manually
pull its cleanup outside the expression, instead keep a list of the cleanups
which we'll need to emit when we get to the end of the full-expression. Also
emit those cleanups early, as EH-only cleanups, to cover the case that the
full-expression does not terminate normally. This allows IR generation to
properly model temporary lifetime when multiple temporaries are extended by the
same declaration.
We have a pre-existing bug where an exception thrown from a temporary's
destructor does not clean up lifetime-extended temporaries created in the same
expression and extended to automatic storage duration; that is not fixed by
this patch.
llvm-svn: 183859
Diffstat (limited to 'clang/lib/CodeGen/CodeGenFunction.h')
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 080c471..7bbf788 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -241,6 +241,18 @@ public: llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags; EHScopeStack EHStack; + llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack; + + /// Header for data within LifetimeExtendedCleanupStack. + struct LifetimeExtendedCleanupHeader { + /// The size of the following cleanup object. + size_t Size : 29; + /// The kind of cleanup to push: a value from the CleanupKind enumeration. + unsigned Kind : 3; + + size_t getSize() const { return Size; } + CleanupKind getKind() const { return static_cast<CleanupKind>(Kind); } + }; /// i32s containing the indexes of the cleanup destinations. llvm::AllocaInst *NormalCleanupDest; @@ -376,6 +388,23 @@ public: initFullExprCleanup(); } + /// \brief Queue a cleanup to be pushed after finishing the current + /// full-expression. + template <class T, class A0, class A1, class A2, class A3> + void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) { + assert(!isInConditionalBranch() && "can't defer conditional cleanup"); + + LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind }; + + size_t OldSize = LifetimeExtendedCleanupStack.size(); + LifetimeExtendedCleanupStack.resize( + LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size); + + char *Buffer = &LifetimeExtendedCleanupStack[OldSize]; + new (Buffer) LifetimeExtendedCleanupHeader(Header); + new (Buffer + sizeof(Header)) T(a0, a1, a2, a3); + } + /// Set up the last cleaup that was pushed as a conditional /// full-expression cleanup. void initFullExprCleanup(); @@ -421,6 +450,7 @@ public: /// will be executed once the scope is exited. class RunCleanupsScope { EHScopeStack::stable_iterator CleanupStackDepth; + size_t LifetimeExtendedCleanupStackSize; bool OldDidCallStackSave; protected: bool PerformCleanup; @@ -438,6 +468,8 @@ public: : PerformCleanup(true), CGF(CGF) { CleanupStackDepth = CGF.EHStack.stable_begin(); + LifetimeExtendedCleanupStackSize = + CGF.LifetimeExtendedCleanupStack.size(); OldDidCallStackSave = CGF.DidCallStackSave; CGF.DidCallStackSave = false; } @@ -447,7 +479,8 @@ public: ~RunCleanupsScope() { if (PerformCleanup) { CGF.DidCallStackSave = OldDidCallStackSave; - CGF.PopCleanupBlocks(CleanupStackDepth); + CGF.PopCleanupBlocks(CleanupStackDepth, + LifetimeExtendedCleanupStackSize); } } @@ -461,7 +494,8 @@ public: void ForceCleanup() { assert(PerformCleanup && "Already forced cleanup"); CGF.DidCallStackSave = OldDidCallStackSave; - CGF.PopCleanupBlocks(CleanupStackDepth); + CGF.PopCleanupBlocks(CleanupStackDepth, + LifetimeExtendedCleanupStackSize); PerformCleanup = false; } }; @@ -513,10 +547,16 @@ public: }; - /// PopCleanupBlocks - Takes the old cleanup stack size and emits - /// the cleanup blocks that have been added. + /// \brief Takes the old cleanup stack size and emits the cleanup blocks + /// that have been added. void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize); + /// \brief Takes the old cleanup stack size and emits the cleanup blocks + /// that have been added, then adds all lifetime-extended cleanups from + /// the given position to the stack. + void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize, + size_t OldLifetimeExtendedStackSize); + void ResolveBranchFixups(llvm::BasicBlock *Target); /// The given basic block lies in the current EH scope, but may be a @@ -988,6 +1028,9 @@ public: llvm::Value *addr, QualType type); void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); + void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr, + QualType type, Destroyer *destroyer, + bool useEHCleanupForArray); void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); llvm::Function *generateDestroyHelper(llvm::Constant *addr, |