aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGDecl.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-05-17 15:52:46 +0000
committerDouglas Gregor <dgregor@apple.com>2010-05-17 15:52:46 +0000
commit3d91bbcdab155181556969cad6ec97014405aced (patch)
tree0ad09340028c6dc86c10cc9fdc7aa014b07502ad /lib/CodeGen/CGDecl.cpp
parent79a9ad8e5eec3696989354be13a74a1106f64f72 (diff)
Ensure that destructors are called for NRVO'd objects when the
function does not return. Thanks to Eli for pointing out this corner case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103941 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGDecl.cpp')
-rw-r--r--lib/CodeGen/CGDecl.cpp34
1 files changed, 31 insertions, 3 deletions
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index ae05fc5c84..611ebed5a3 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -399,6 +399,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
bool IsSimpleConstantInitializer = false;
bool NRVO = false;
+ llvm::Value *NRVOFlag = 0;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
@@ -430,6 +431,21 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// return slot, so that we can elide the copy when returning this
// variable (C++0x [class.copy]p34).
DeclPtr = ReturnValue;
+
+ if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+ if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
+ // Create a flag that is used to indicate when the NRVO was applied
+ // to this variable. Set it to zero to indicate that NRVO was not
+ // applied.
+ const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext);
+ llvm::Value *Zero = llvm::ConstantInt::get(BoolTy, 0);
+ NRVOFlag = CreateTempAlloca(BoolTy, "nrvo");
+ Builder.CreateStore(Zero, NRVOFlag);
+
+ // Record the NRVO flag for this variable.
+ NRVOFlags[&D] = NRVOFlag;
+ }
+ }
} else {
if (isByRef)
LTy = BuildByRefType(&D);
@@ -660,7 +676,8 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
if (const RecordType *RT = DtorTy->getAs<RecordType>())
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->hasTrivialDestructor()) {
- // Note: We suppress the destructor call when this is an NRVO variable.
+ // Note: We suppress the destructor call when the corresponding NRVO
+ // flag has been set.
llvm::Value *Loc = DeclPtr;
if (isByRef)
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
@@ -693,10 +710,21 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
}
} else {
- if (!NRVO) {
+ {
+ // Normal destruction.
+ DelayedCleanupBlock Scope(*this);
+
+ if (NRVO) {
+ // If we exited via NRVO, we skip the destructor call.
+ llvm::BasicBlock *NoNRVO = createBasicBlock("nrvo.unused");
+ Builder.CreateCondBr(Builder.CreateLoad(NRVOFlag, "nrvo.val"),
+ Scope.getCleanupExitBlock(),
+ NoNRVO);
+ EmitBlock(NoNRVO);
+ }
+
// We don't call the destructor along the normal edge if we're
// applying the NRVO.
- DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
Loc);