diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-06-21 17:03:29 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-06-21 17:03:29 +0000 |
commit | 03e80030515c800d1ab44125b9052dfffd1bd04c (patch) | |
tree | 4ef971a4ce700937aabf19c08f2bfd4f826a7a91 /lib/StaticAnalyzer | |
parent | 65aa6885818d4b4eea2e5a9d12085b2398148662 (diff) |
Introduce a new AST node describing reference binding to temporaries.
MaterializeTemporaryExpr captures a reference binding to a temporary
value, making explicit that the temporary value (a prvalue) needs to
be materialized into memory so that its address can be used. The
intended AST invariant here is that a reference will always bind to a
glvalue, and MaterializeTemporaryExpr will be used to convert prvalues
into glvalues for that binding to happen. For example, given
const int& r = 1.0;
The initializer of "r" will be a MaterializeTemporaryExpr whose
subexpression is an implicit conversion from the double literal "1.0"
to an integer value.
IR generation benefits most from this new node, since it was
previously guessing (badly) when to materialize temporaries for the
purposes of reference binding. There are likely more refactoring and
cleanups we could perform there, but the introduction of
MaterializeTemporaryExpr fixes PR9565, a case where IR generation
would effectively bind a const reference directly to a bitfield in a
struct. Addresses <rdar://problem/9552231>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133521 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp | 27 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/Environment.cpp | 3 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 24 |
3 files changed, 35 insertions, 19 deletions
diff --git a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp index e4e5f54770..de6da4f8c3 100644 --- a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp @@ -237,8 +237,11 @@ const GRState *IteratorsChecker::invalidateIterators(const GRState *state, const GRState *IteratorsChecker::handleAssign(const GRState *state, const Expr *lexp, const Expr *rexp, const LocationContext *LC) const { // Skip the cast if present. - if (isa<ImplicitCastExpr>(lexp)) - lexp = dyn_cast<ImplicitCastExpr>(lexp)->getSubExpr(); + if (const MaterializeTemporaryExpr *M + = dyn_cast<MaterializeTemporaryExpr>(lexp)) + lexp = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp)) + lexp = ICE->getSubExpr(); SVal sv = state->getSVal(lexp); const MemRegion *MR = sv.getAsRegion(); if (!MR) @@ -260,8 +263,11 @@ const GRState *IteratorsChecker::handleAssign(const GRState *state, const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const { // Assume unknown until we find something definite. state = state->set<IteratorState>(MR, RefState::getUnknown()); - if (isa<ImplicitCastExpr>(rexp)) - rexp = dyn_cast<ImplicitCastExpr>(rexp)->getSubExpr(); + if (const MaterializeTemporaryExpr *M + = dyn_cast<MaterializeTemporaryExpr>(rexp)) + rexp = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(rexp)) + rexp = ICE->getSubExpr(); // Need to handle three cases: MemberCall, copy, copy with addition. if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) { // Handle MemberCall. @@ -347,8 +353,10 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const { E = CE->getArg(0); } } - if (isa<ImplicitCastExpr>(E)) - E = dyn_cast<ImplicitCastExpr>(E)->getSubExpr(); + if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) + E = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + E = ICE->getSubExpr(); // If it isn't one of our types, don't do anything. if (getTemplateKind(E->getType()) != VectorIteratorKind) return NULL; @@ -520,8 +528,11 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS, if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) { if (CE->getNumArgs() == 1) { const Expr *E = CE->getArg(0); - if (isa<ImplicitCastExpr>(E)) - InitEx = dyn_cast<ImplicitCastExpr>(E)->getSubExpr(); + if (const MaterializeTemporaryExpr *M + = dyn_cast<MaterializeTemporaryExpr>(E)) + E = M->GetTemporaryExpr(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + InitEx = ICE->getSubExpr(); state = handleAssign(state, MR, InitEx, C.getPredecessor()->getLocationContext()); } diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp index 48f126bfd8..3961c7b952 100644 --- a/lib/StaticAnalyzer/Core/Environment.cpp +++ b/lib/StaticAnalyzer/Core/Environment.cpp @@ -83,6 +83,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder, case Stmt::CXXBindTemporaryExprClass: E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); continue; + case Stmt::MaterializeTemporaryExprClass: + E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(); + continue; // Handle all other Stmt* using a lookup. default: break; diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 21efbac699..4aa5e350bc 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -700,6 +700,16 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } + case Expr::MaterializeTemporaryExprClass: { + const MaterializeTemporaryExpr *Materialize + = cast<MaterializeTemporaryExpr>(S); + if (!Materialize->getType()->isRecordType()) + CreateCXXTemporaryObject(Materialize->GetTemporaryExpr(), Pred, Dst); + else + Visit(Materialize->GetTemporaryExpr(), Pred, Dst); + break; + } + case Stmt::InitListExprClass: VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); break; @@ -2306,17 +2316,9 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, // time a function is called those values may not be current. ExplodedNodeSet Tmp; - if (InitEx) { - if (VD->getType()->isReferenceType() && !InitEx->isLValue()) { - // If the initializer is C++ record type, it should already has a - // temp object. - if (!InitEx->getType()->isRecordType()) - CreateCXXTemporaryObject(InitEx, Pred, Tmp); - else - Tmp.Add(Pred); - } else - Visit(InitEx, Pred, Tmp); - } else + if (InitEx) + Visit(InitEx, Pred, Tmp); + else Tmp.Add(Pred); ExplodedNodeSet Tmp2; |