[cfe-commits] r103941 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGStmt.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/nrvo.cpp

Douglas Gregor dgregor at apple.com
Mon May 17 08:52:46 PDT 2010


Author: dgregor
Date: Mon May 17 10:52:46 2010
New Revision: 103941

URL: http://llvm.org/viewvc/llvm-project?rev=103941&view=rev
Log:
Ensure that destructors are called for NRVO'd objects when the
function does not return. Thanks to Eli for pointing out this corner
case.

Modified:
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGenCXX/nrvo.cpp

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Mon May 17 10:52:46 2010
@@ -399,6 +399,7 @@
   bool IsSimpleConstantInitializer = false;
 
   bool NRVO = false;
+  llvm::Value *NRVOFlag = 0;
   llvm::Value *DeclPtr;
   if (Ty->isConstantSizeType()) {
     if (!Target.useGlobalsForAutomaticVariables()) {
@@ -430,6 +431,21 @@
         // 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 @@
   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 @@
             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);
 

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Mon May 17 10:52:46 2010
@@ -612,6 +612,14 @@
     // Apply the named return value optimization for this return statement,
     // which means doing nothing: the appropriate result has already been
     // constructed into the NRVO variable.
+    
+    // If there is an NRVO flag for this variable, set it to 1 into indicate
+    // that the cleanup code should not destroy the variable.
+    if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()]) {
+      const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext);
+      llvm::Value *One = llvm::ConstantInt::get(BoolTy, 1);
+      Builder.CreateStore(One, NRVOFlag);
+    }
   } else if (!ReturnValue) {
     // Make sure not to return anything, but evaluate the expression
     // for side effects.

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon May 17 10:52:46 2010
@@ -107,6 +107,11 @@
 
   bool Exceptions;
   bool CatchUndefined;
+  
+  /// \brief A mapping from NRVO variables to the flags used to indicate
+  /// when the NRVO has been applied to this variable.
+  llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
+  
 public:
   /// ObjCEHValueStack - Stack of Objective-C exception values, used for
   /// rethrows.

Modified: cfe/trunk/test/CodeGenCXX/nrvo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/nrvo.cpp?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/nrvo.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/nrvo.cpp Mon May 17 10:52:46 2010
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s
 // RUN: %clang_cc1 -emit-llvm -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
 
 // Test code generation for the named return value optimization.
@@ -15,9 +15,12 @@
   X x;
   // CHECK-NOT: call void @_ZN1XD1Ev
   // CHECK: ret void
+  // CHECK-EH: br label
+  // CHECK-EH: call void @_ZN1XD1Ev
+  // CHECK-EH: br label
+  // CHECK-EH: invoke void @_ZN1XD1Ev
   // CHECK-EH: ret void
   return x;
-  // CHECK-EH: invoke void @_ZN1XD1Ev
 }
 
 // CHECK: define void @_Z5test1b(
@@ -63,3 +66,19 @@
   X x;
   return x;
 }
+
+extern "C" void exit(int) throw();
+
+// CHECK: define void @_Z5test4b
+X test4(bool B) {
+  {
+    // CHECK: tail call void @_ZN1XC1Ev
+    X x;
+    // CHECK: br i1
+    if (B)
+      return x;
+  }
+  // CHECK: tail call void @_ZN1XD1Ev
+  // CHECK: tail call void @exit(i32 1)
+  exit(1);
+}





More information about the cfe-commits mailing list