Previously, we'd just keep constraints around forever, which means we'd
never be able to merge paths that differed only in constraints on dead
symbols.
Because we now allow constraints on symbolic expressions, not just single
symbols, this requires changing SymExpr::symbol_iterator to include
intermediate symbol nodes in its traversal, not just the SymbolData leaf
nodes.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163444
91177308-0d34-0410-b5e6-
96231b3b80d8
SymReaper);
NewState.setStore(newStore);
SymReaper.setReapedStore(newStore);
-
- return getPersistentState(NewState);
+
+ ProgramStateRef Result = getPersistentState(NewState);
+ return ConstraintMgr->removeDeadBindings(Result, SymReaper);
}
ProgramStateRef ProgramStateManager::MarshalState(ProgramStateRef state,
bool Tainted = false;
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
SI != SE; ++SI) {
- assert(isa<SymbolData>(*SI));
+ if (!isa<SymbolData>(*SI))
+ continue;
+
const TaintTagType *Tag = get<TaintMap>(*SI);
Tainted = (Tag && *Tag == Kind);
SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
itr.push_back(SE);
- while (!isa<SymbolData>(itr.back())) expand();
}
SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
- assert(isa<SymbolData>(itr.back()));
- itr.pop_back();
- if (!itr.empty())
- while (!isa<SymbolData>(itr.back())) expand();
+ expand();
return *this;
}
SymbolRef SymExpr::symbol_iterator::operator*() {
assert(!itr.empty() && "attempting to dereference an 'end' iterator");
- return cast<SymbolData>(itr.back());
+ return itr.back();
}
void SymExpr::symbol_iterator::expand() {
--- /dev/null
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.DumpTraversal %s | FileCheck %s
+
+int a();
+int b();
+int c();
+
+void testRemoveDeadBindings() {
+ int i = a();
+ if (i)
+ a();
+ else
+ b();
+
+ // At this point the symbol bound to 'i' is dead.
+ // The effects of a() and b() are identical (they both invalidate globals).
+ // We should unify the two paths here and only get one end-of-path node.
+ c();
+}
+
+// CHECK: --END PATH--
+// CHECK-NOT: --END PATH--
\ No newline at end of file