aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-05-06 16:48:20 +0000
committerJordan Rose <jordan_rose@apple.com>2013-05-06 16:48:20 +0000
commit6376703eb3325fe41233aed234fde81164af42a1 (patch)
tree0f214678f63f7f3eb4dcfd44bc68d024a7def91f
parent2624b8157660902303bfce5551cfdd38272d01e5 (diff)
[analyzer] Handle CXXTemporaryObjectExprs in compound literals.
This occurs because in C++11 the compound literal syntax can trigger a constructor call via list-initialization. That is, "Point{x, y}" and "(Point){x, y}" end up being equivalent. If this occurs, the inner CXXConstructExpr will have already handled the object construction; the CompoundLiteralExpr just needs to propagate that value forwards. <rdar://problem/13804098> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181213 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp44
-rw-r--r--test/Analysis/temporaries.cpp35
2 files changed, 59 insertions, 20 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 2d52c01e1d..67aeab6003 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -403,26 +403,32 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
ExplodedNodeSet &Dst) {
StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
- const InitListExpr *ILE
- = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
+ ProgramStateRef State = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+
+ const Expr *Init = CL->getInitializer();
+ SVal V = State->getSVal(CL->getInitializer(), LCtx);
- ProgramStateRef state = Pred->getState();
- SVal ILV = state->getSVal(ILE, Pred->getLocationContext());
- const LocationContext *LC = Pred->getLocationContext();
- state = state->bindCompoundLiteral(CL, LC, ILV);
-
- // Compound literal expressions are a GNU extension in C++.
- // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues,
- // and like temporary objects created by the functional notation T()
- // CLs are destroyed at the end of the containing full-expression.
- // HOWEVER, an rvalue of array type is not something the analyzer can
- // reason about, since we expect all regions to be wrapped in Locs.
- // So we treat array CLs as lvalues as well, knowing that they will decay
- // to pointers as soon as they are used.
- if (CL->isGLValue() || CL->getType()->isArrayType())
- B.generateNode(CL, Pred, state->BindExpr(CL, LC, state->getLValue(CL, LC)));
- else
- B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV));
+ if (isa<CXXConstructExpr>(Init)) {
+ // No work needed. Just pass the value up to this expression.
+ } else {
+ assert(isa<InitListExpr>(Init));
+ Loc CLLoc = State->getLValue(CL, LCtx);
+ State = State->bindLoc(CLLoc, V);
+
+ // Compound literal expressions are a GNU extension in C++.
+ // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues,
+ // and like temporary objects created by the functional notation T()
+ // CLs are destroyed at the end of the containing full-expression.
+ // HOWEVER, an rvalue of array type is not something the analyzer can
+ // reason about, since we expect all regions to be wrapped in Locs.
+ // So we treat array CLs as lvalues as well, knowing that they will decay
+ // to pointers as soon as they are used.
+ if (CL->isGLValue() || CL->getType()->isArrayType())
+ V = CLLoc;
+ }
+
+ B.generateNode(CL, Pred, State->BindExpr(CL, LCtx, V));
}
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index 32a4d3bef4..efc0825470 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
extern bool clang_analyzer_eval(bool);
@@ -76,3 +77,35 @@ namespace rdar13281951 {
}
}
+namespace compound_literals {
+ struct POD {
+ int x, y;
+ };
+ struct HasCtor {
+ HasCtor(int x, int y) : x(x), y(y) {}
+ int x, y;
+ };
+ struct HasDtor {
+ int x, y;
+ ~HasDtor();
+ };
+ struct HasCtorDtor {
+ HasCtorDtor(int x, int y) : x(x), y(y) {}
+ ~HasCtorDtor();
+ int x, y;
+ };
+
+ void test() {
+ clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}}
+
+#if __cplusplus >= 201103L
+ clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}}
+
+ // FIXME: should be TRUE, but we don't inline the constructors of
+ // temporaries because we can't model their destructors yet.
+ clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}}
+#endif
+ }
+}
+