mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-21 20:45:53 -04:00

SymbolReaper now realizes that our liveness analysis isn't sharp enough to discriminate between liveness of, say, variables and their fields. Surprisingly, this didn't quite work before: having a variable live only through Environment (eg., calling a C++ method on a local variable as the last action ever performed on that variable) would not keep the region value symbol of a field of that variable alive. It would have been broken in the opposite direction as well, but both Environment and RegionStore use the scanReachableSymbols mechanism for finding live symbols regions within their values, and due to that they accidentally end up marking the whole chain of super-regions as live when at least one sub-region is known to be live. It is now a direct responsibility of SymbolReaper to maintain this invariant, and a unit test was added in order to make sure it stays that way. Differential Revision: https://reviews.llvm.org/D56632 rdar://problem/46914108 llvm-svn: 351499
61 lines
1.5 KiB
C++
61 lines
1.5 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
|
|
|
|
void clang_analyzer_eval(int);
|
|
void clang_analyzer_warnOnDeadSymbol(int);
|
|
|
|
namespace test_dead_region_with_live_subregion_in_environment {
|
|
int glob;
|
|
|
|
struct A {
|
|
int x;
|
|
|
|
void foo() {
|
|
// FIXME: Maybe just let clang_analyzer_eval() work within callees already?
|
|
// The glob variable shouldn't keep our symbol alive because
|
|
// 'x != 0' is concrete 'true'.
|
|
glob = (x != 0);
|
|
}
|
|
};
|
|
|
|
void test_A(A a) {
|
|
if (a.x == 0)
|
|
return;
|
|
|
|
clang_analyzer_warnOnDeadSymbol(a.x);
|
|
|
|
// What we're testing is that a.x is alive until foo() exits.
|
|
a.foo(); // no-warning // (i.e., no 'SYMBOL DEAD' yet)
|
|
|
|
// Let's see if constraints on a.x were known within foo().
|
|
clang_analyzer_eval(glob); // expected-warning{{TRUE}}
|
|
// expected-warning@-1{{SYMBOL DEAD}}
|
|
}
|
|
|
|
struct B {
|
|
A a;
|
|
int y;
|
|
};
|
|
|
|
A &noop(A &a) {
|
|
// This function ensures that the 'b' expression within its argument
|
|
// would be cleaned up before its call, so that only 'b.a' remains
|
|
// in the Environment.
|
|
return a;
|
|
}
|
|
|
|
|
|
void test_B(B b) {
|
|
if (b.a.x == 0)
|
|
return;
|
|
|
|
clang_analyzer_warnOnDeadSymbol(b.a.x);
|
|
|
|
// What we're testing is that b.a.x is alive until foo() exits.
|
|
noop(b.a).foo(); // no-warning // (i.e., no 'SYMBOL DEAD' yet)
|
|
|
|
// Let's see if constraints on a.x were known within foo().
|
|
clang_analyzer_eval(glob); // expected-warning{{TRUE}}
|
|
// expected-warning@-1{{SYMBOL DEAD}}
|
|
}
|
|
} // namespace test_dead_region_with_live_subregion_in_environment
|