From 6376703eb3325fe41233aed234fde81164af42a1 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Mon, 6 May 2013 16:48:20 +0000 Subject: [PATCH] [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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181213 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/ExprEngineC.cpp | 44 ++++++++++++++----------- test/Analysis/temporaries.cpp | 35 +++++++++++++++++++- 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(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(Init)) { + // No work needed. Just pass the value up to this expression. + } else { + assert(isa(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 + } +} + -- 2.40.0