1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
2 
3 void clang_analyzer_eval(int);
4 void clang_analyzer_warnOnDeadSymbol(int);
5 
6 namespace test_dead_region_with_live_subregion_in_environment {
7 int glob;
8 
9 struct A {
10   int x;
11 
footest_dead_region_with_live_subregion_in_environment::A12   void foo() {
13     // FIXME: Maybe just let clang_analyzer_eval() work within callees already?
14     // The glob variable shouldn't keep our symbol alive because
15     // 'x != 0' is concrete 'true'.
16     glob = (x != 0);
17   }
18 };
19 
test_A(A a)20 void test_A(A a) {
21   if (a.x == 0)
22     return;
23 
24   clang_analyzer_warnOnDeadSymbol(a.x);
25 
26   // What we're testing is that a.x is alive until foo() exits.
27   a.foo(); // no-warning // (i.e., no 'SYMBOL DEAD' yet)
28 
29   // Let's see if constraints on a.x were known within foo().
30   clang_analyzer_eval(glob); // expected-warning{{TRUE}}
31                              // expected-warning@-1{{SYMBOL DEAD}}
32 }
33 
34 struct B {
35   A a;
36   int y;
37 };
38 
noop(A & a)39 A &noop(A &a) {
40   // This function ensures that the 'b' expression within its argument
41   // would be cleaned up before its call, so that only 'b.a' remains
42   // in the Environment.
43   return a;
44 }
45 
46 
test_B(B b)47 void test_B(B b) {
48   if (b.a.x == 0)
49     return;
50 
51   clang_analyzer_warnOnDeadSymbol(b.a.x);
52 
53   // What we're testing is that b.a.x is alive until foo() exits.
54   noop(b.a).foo(); // no-warning // (i.e., no 'SYMBOL DEAD' yet)
55 
56   // Let's see if constraints on a.x were known within foo().
57   clang_analyzer_eval(glob); // expected-warning{{TRUE}}
58                              // expected-warning@-1{{SYMBOL DEAD}}
59 }
60 } // namespace test_dead_region_with_live_subregion_in_environment
61