r214292 - Fix some cases of incorrect handling of lifetime extended temporaries.

Manuel Klimek klimek at google.com
Wed Jul 30 01:34:42 PDT 2014


Author: klimek
Date: Wed Jul 30 03:34:42 2014
New Revision: 214292

URL: http://llvm.org/viewvc/llvm-project?rev=214292&view=rev
Log:
Fix some cases of incorrect handling of lifetime extended temporaries.

MaterializeTemporaryExpr already contains information about the lifetime
of the temporary; if the lifetime is not the full statement, we do not
want to emit a destructor at the end of the full statement for it.

Modified:
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/test/Analysis/cfg.cpp

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=214292&r1=214291&r2=214292&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Wed Jul 30 03:34:42 2014
@@ -1000,21 +1000,17 @@ CFGBlock *CFGBuilder::addInitializer(CXX
   if (!BuildOpts.AddInitializers)
     return Block;
 
-  bool IsReference = false;
   bool HasTemporaries = false;
 
   // Destructors of temporaries in initialization expression should be called
   // after initialization finishes.
   Expr *Init = I->getInit();
   if (Init) {
-    if (FieldDecl *FD = I->getAnyMember())
-      IsReference = FD->getType()->isReferenceType();
     HasTemporaries = isa<ExprWithCleanups>(Init);
 
     if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
       // Generate destructors for temporaries in initialization expression.
-      VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
-          IsReference);
+      VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr());
     }
   }
 
@@ -1946,7 +1942,6 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(D
     return Block;
   }
 
-  bool IsReference = false;
   bool HasTemporaries = false;
 
   // Guard static initializers under a branch.
@@ -1968,13 +1963,11 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(D
   // after initialization finishes.
   Expr *Init = VD->getInit();
   if (Init) {
-    IsReference = VD->getType()->isReferenceType();
     HasTemporaries = isa<ExprWithCleanups>(Init);
 
     if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
       // Generate destructors for temporaries in initialization expression.
-      VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
-          IsReference);
+      VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr());
     }
   }
 
@@ -3492,13 +3485,32 @@ tryAgain:
       E = cast<CastExpr>(E)->getSubExpr();
       goto tryAgain;
 
+    case Stmt::CXXFunctionalCastExprClass:
+      // For functional cast we want BindToTemporary to be passed further.
+      E = cast<CXXFunctionalCastExpr>(E)->getSubExpr();
+      goto tryAgain;
+
     case Stmt::ParenExprClass:
       E = cast<ParenExpr>(E)->getSubExpr();
       goto tryAgain;
 
-    case Stmt::MaterializeTemporaryExprClass:
-      E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
+    case Stmt::MaterializeTemporaryExprClass: {
+      const MaterializeTemporaryExpr* MTE = cast<MaterializeTemporaryExpr>(E);
+      BindToTemporary = (MTE->getStorageDuration() != SD_FullExpression);
+      SmallVector<const Expr *, 2> CommaLHSs;
+      SmallVector<SubobjectAdjustment, 2> Adjustments;
+      // Find the expression whose lifetime needs to be extended.
+      E = const_cast<Expr *>(
+          cast<MaterializeTemporaryExpr>(E)
+              ->GetTemporaryExpr()
+              ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
+      // Visit the skipped comma operator left-hand sides for other temporaries.
+      for (const Expr *CommaLHS : CommaLHSs) {
+        VisitForTemporaryDtors(const_cast<Expr *>(CommaLHS),
+                               /*BindToTemporary=*/false);
+      }
       goto tryAgain;
+    }
 
     case Stmt::BlockExprClass:
       // Don't recurse into blocks; their subexpressions don't get evaluated

Modified: cfe/trunk/test/Analysis/cfg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg.cpp?rev=214292&r1=214291&r2=214292&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg.cpp (original)
+++ cfe/trunk/test/Analysis/cfg.cpp Wed Jul 30 03:34:42 2014
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++11 %s > %t 2>&1
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1
 // RUN: FileCheck --input-file=%t %s
 
 // CHECK-LABEL: void checkWrap(int i)
@@ -377,6 +377,61 @@ void test_placement_new_array() {
 }
 
 
+// CHECK-LABEL: void test_lifetime_extended_temporaries()
+// CHECK: [B1]
+struct LifetimeExtend { LifetimeExtend(int); ~LifetimeExtend(); };
+struct Aggregate { const LifetimeExtend a; const LifetimeExtend b; };
+struct AggregateRef { const LifetimeExtend &a; const LifetimeExtend &b; };
+void test_lifetime_extended_temporaries() {
+  // CHECK: LifetimeExtend(1);
+  // CHECK-NEXT: : 1
+  // CHECK-NEXT: ~LifetimeExtend()
+  // CHECK-NOT: ~LifetimeExtend()
+  {
+    const LifetimeExtend &l = LifetimeExtend(1);
+    1;
+  }
+  // CHECK: LifetimeExtend(2)
+  // CHECK-NEXT: ~LifetimeExtend()
+  // CHECK-NEXT: : 2
+  // CHECK-NOT: ~LifetimeExtend()
+  {
+    // No life-time extension.
+    const int &l = (LifetimeExtend(2), 2);
+    2;
+  }
+  // CHECK: LifetimeExtend(3)
+  // CHECK-NEXT: : 3
+  // CHECK-NEXT: ~LifetimeExtend()
+  // CHECK-NOT: ~LifetimeExtend()
+  {
+    // The last one is lifetime extended.
+    const LifetimeExtend &l = (3, LifetimeExtend(3));
+    3;
+  }
+  // CHECK: LifetimeExtend(4)
+  // CHECK-NEXT: ~LifetimeExtend()
+  // CHECK-NEXT: ~LifetimeExtend()
+  // CHECK-NEXT: : 4
+  // CHECK-NOT: ~LifetimeExtend()
+  {
+    Aggregate a{LifetimeExtend(4), LifetimeExtend(4)};
+    4;
+  }
+  // CHECK: LifetimeExtend(5)
+  // CHECK-NEXT: : 5
+  // FIXME: We want to emit the destructors of the lifetime
+  // extended variables here.
+  // CHECK-NOT: ~LifetimeExtend()
+  {
+    AggregateRef a{LifetimeExtend(5), LifetimeExtend(5)};
+    5;
+  }
+  // FIXME: Add tests for lifetime extension via subobject
+  // references (LifetimeExtend().some_member).
+}
+
+
 // CHECK-LABEL: int *PR18472()
 // CHECK: [B2 (ENTRY)]
 // CHECK-NEXT:   Succs (1): B1





More information about the cfe-commits mailing list