Add tests and fix lifetime extensions in the face of the comma operator.
http://reviews.llvm.org/D4696
Files:
lib/Analysis/CFG.cpp
test/Analysis/cfg.cpp
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -1000,21 +1000,17 @@
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 @@
return Block;
}
- bool IsReference = false;
bool HasTemporaries = false;
// Guard static initializers under a branch.
@@ -1968,13 +1963,11 @@
// 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 @@
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
Index: test/Analysis/cfg.cpp
===================================================================
--- test/Analysis/cfg.cpp
+++ test/Analysis/cfg.cpp
@@ -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,42 @@
}
+// CHECK-LABEL: void test_lifetime_extended_temporaries()
+// CHECK: [B1]
+// CHECK: LifetimeExtend(1);
+// CHECK-NEXT: : 1
+// CHECK-NEXT: ~LifetimeExtend()
+// CHECK-NOT: ~LifetimeExtend()
+// CHECK: LifetimeExtend(2)
+// CHECK-NEXT: ~LifetimeExtend()
+// CHECK-NEXT: : 2
+// CHECK-NOT: ~LifetimeExtend()
+// CHECK: LifetimeExtend(3)
+// CHECK-NEXT: : 3
+// CHECK-NEXT: ~LifetimeExtend()
+// CHECK-NOT: ~LifetimeExtend()
+
+struct LifetimeExtend { LifetimeExtend(int); ~LifetimeExtend(); };
+void test_lifetime_extended_temporaries() {
+ {
+ const LifetimeExtend &l = LifetimeExtend(1);
+ 1;
+ }
+ {
+ // No life-time extension.
+ const int &l = (LifetimeExtend(2), 2);
+ 2;
+ }
+ {
+ // The last one is lifetime extended.
+ const LifetimeExtend &l = (3, LifetimeExtend(3));
+ 3;
+ }
+ // FIXME: Add tests for lifetime extension via subobject
+ // references (LifetimeExtend().some_member).
+}
+
+
// CHECK-LABEL: int *PR18472()
// CHECK: [B2 (ENTRY)]
// CHECK-NEXT: Succs (1): B1
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits