diff options
author | George Karpenkov <ekarpenkov@apple.com> | 2018-03-31 01:20:06 +0000 |
---|---|---|
committer | George Karpenkov <ekarpenkov@apple.com> | 2018-03-31 01:20:06 +0000 |
commit | 137ca91f52e0eccd866da5f877563d930df30079 (patch) | |
tree | 78e53ff3766fab484000332804ce264cffe66164 /clang/lib/Analysis | |
parent | db83aceb0686c25c1a5d3db2e776bc8c9b0de3ee (diff) | |
download | bcm5719-llvm-137ca91f52e0eccd866da5f877563d930df30079.tar.gz bcm5719-llvm-137ca91f52e0eccd866da5f877563d930df30079.zip |
[analyzer] Fix liveness calculation for C++17 structured bindings
C++ structured bindings for non-tuple-types are defined in a peculiar
way, where the resulting declaration is not a VarDecl, but a
BindingDecl.
That means a lot of existing machinery stops working.
rdar://36912381
Differential Revision: https://reviews.llvm.org/D44956
llvm-svn: 328910
Diffstat (limited to 'clang/lib/Analysis')
-rw-r--r-- | clang/lib/Analysis/LiveVariables.cpp | 83 |
1 files changed, 59 insertions, 24 deletions
diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp index f557a74af00..d03d2a052d2 100644 --- a/clang/lib/Analysis/LiveVariables.cpp +++ b/clang/lib/Analysis/LiveVariables.cpp @@ -77,6 +77,7 @@ public: AnalysisDeclContext &analysisContext; llvm::ImmutableSet<const Stmt *>::Factory SSetFact; llvm::ImmutableSet<const VarDecl *>::Factory DSetFact; + llvm::ImmutableSet<const BindingDecl *>::Factory BSetFact; llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness; llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness; llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness; @@ -97,6 +98,7 @@ public: : analysisContext(ac), SSetFact(false), // Do not canonicalize ImmutableSets by default. DSetFact(false), // This is a *major* performance win. + BSetFact(false), killAtAssign(KillAtAssign) {} }; } @@ -114,6 +116,12 @@ bool LiveVariables::LivenessValues::isLive(const Stmt *S) const { } bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const { + if (const auto *DD = dyn_cast<DecompositionDecl>(D)) { + bool alive = false; + for (const BindingDecl *BD : DD->bindings()) + alive |= liveBindings.contains(BD); + return alive; + } return liveDecls.contains(D); } @@ -145,14 +153,19 @@ LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA, DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()), DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()); + llvm::ImmutableSetRef<const BindingDecl *> + BSetRefA(valsA.liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory()), + BSetRefB(valsB.liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory()); SSetRefA = mergeSets(SSetRefA, SSetRefB); DSetRefA = mergeSets(DSetRefA, DSetRefB); + BSetRefA = mergeSets(BSetRefA, BSetRefB); // asImmutableSet() canonicalizes the tree, allowing us to do an easy // comparison afterwards. return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(), - DSetRefA.asImmutableSet()); + DSetRefA.asImmutableSet(), + BSetRefA.asImmutableSet()); } bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const { @@ -322,6 +335,11 @@ void TransferFunctions::Visit(Stmt *S) { } } +static bool writeShouldKill(const VarDecl *VD) { + return VD && !VD->getType()->isReferenceType() && + !isAlwaysAlive(VD); +} + void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { if (B->isAssignmentOp()) { if (!LV.killAtAssign) @@ -329,21 +347,25 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { // Assigning to a variable? Expr *LHS = B->getLHS()->IgnoreParens(); - - if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) - if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - // Assignments to references don't kill the ref's address - if (VD->getType()->isReferenceType()) - return; - - if (!isAlwaysAlive(VD)) { - // The variable is now dead. + + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) { + const Decl* D = DR->getDecl(); + bool Killed = false; + + if (const BindingDecl* BD = dyn_cast<BindingDecl>(D)) { + Killed = !BD->getType()->isReferenceType(); + if (Killed) + val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD); + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { + Killed = writeShouldKill(VD); + if (Killed) val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); - } - if (observer) - observer->observerKill(DR); } + + if (Killed && observer) + observer->observerKill(DR); + } } } @@ -357,17 +379,28 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *BE) { } void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) { - if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) - if (!isAlwaysAlive(D) && LV.inAssignment.find(DR) == LV.inAssignment.end()) - val.liveDecls = LV.DSetFact.add(val.liveDecls, D); + const Decl* D = DR->getDecl(); + bool InAssignment = LV.inAssignment[DR]; + if (const auto *BD = dyn_cast<BindingDecl>(D)) { + if (!InAssignment) + val.liveBindings = + LV.BSetFact.add(val.liveBindings, cast<BindingDecl>(D)); + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (!InAssignment && !isAlwaysAlive(VD)) + val.liveDecls = LV.DSetFact.add(val.liveDecls, VD); + } } void TransferFunctions::VisitDeclStmt(DeclStmt *DS) { - for (const auto *DI : DS->decls()) - if (const auto *VD = dyn_cast<VarDecl>(DI)) { + for (const auto *DI : DS->decls()) { + if (const auto *DD = dyn_cast<DecompositionDecl>(DI)) { + for (const auto *BD : DD->bindings()) + val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD); + } else if (const auto *VD = dyn_cast<VarDecl>(DI)) { if (!isAlwaysAlive(VD)) val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); } + } } void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) { @@ -422,12 +455,14 @@ void TransferFunctions::VisitUnaryOperator(UnaryOperator *UO) { case UO_PreDec: break; } - - if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) - if (isa<VarDecl>(DR->getDecl())) { + + if (auto *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) { + const Decl *D = DR->getDecl(); + if (isa<VarDecl>(D) || isa<BindingDecl>(D)) { // Treat ++/-- as a kill. observer->observerKill(DR); } + } } LiveVariables::LivenessValues @@ -508,10 +543,10 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC, for (CFGBlock::const_iterator bi = block->begin(), be = block->end(); bi != be; ++bi) { if (Optional<CFGStmt> cs = bi->getAs<CFGStmt>()) { - if (const BinaryOperator *BO = - dyn_cast<BinaryOperator>(cs->getStmt())) { + const Stmt* stmt = cs->getStmt(); + if (const auto *BO = dyn_cast<BinaryOperator>(stmt)) { if (BO->getOpcode() == BO_Assign) { - if (const DeclRefExpr *DR = + if (const auto *DR = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) { LV->inAssignment[DR] = 1; } |