1// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++03 %s
2// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w -std=c++11 %s
3// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DTEMPORARY_DTORS -verify -w -analyzer-config cfg-temporary-dtors=true %s
4
5extern bool clang_analyzer_eval(bool);
6
7struct Trivial {
8  Trivial(int x) : value(x) {}
9  int value;
10};
11
12struct NonTrivial : public Trivial {
13  NonTrivial(int x) : Trivial(x) {}
14  ~NonTrivial();
15};
16
17
18Trivial getTrivial() {
19  return Trivial(42); // no-warning
20}
21
22const Trivial &getTrivialRef() {
23  return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}}
24}
25
26
27NonTrivial getNonTrivial() {
28  return NonTrivial(42); // no-warning
29}
30
31const NonTrivial &getNonTrivialRef() {
32  return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}}
33}
34
35namespace rdar13265460 {
36  struct TrivialSubclass : public Trivial {
37    TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {}
38    int anotherValue;
39  };
40
41  TrivialSubclass getTrivialSub() {
42    TrivialSubclass obj(1);
43    obj.value = 42;
44    obj.anotherValue = -42;
45    return obj;
46  }
47
48  void testImmediate() {
49    TrivialSubclass obj = getTrivialSub();
50
51    clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}}
52    clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}}
53
54    clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}}
55    clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}}
56  }
57
58  void testMaterializeTemporaryExpr() {
59    const TrivialSubclass &ref = getTrivialSub();
60    clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
61
62    const Trivial &baseRef = getTrivialSub();
63    clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}}
64  }
65}
66
67namespace rdar13281951 {
68  struct Derived : public Trivial {
69    Derived(int value) : Trivial(value), value2(-value) {}
70    int value2;
71  };
72
73  void test() {
74    Derived obj(1);
75    obj.value = 42;
76    const Trivial * const &pointerRef = &obj;
77    clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}}
78  }
79}
80
81namespace compound_literals {
82  struct POD {
83    int x, y;
84  };
85  struct HasCtor {
86    HasCtor(int x, int y) : x(x), y(y) {}
87    int x, y;
88  };
89  struct HasDtor {
90    int x, y;
91    ~HasDtor();
92  };
93  struct HasCtorDtor {
94    HasCtorDtor(int x, int y) : x(x), y(y) {}
95    ~HasCtorDtor();
96    int x, y;
97  };
98
99  void test() {
100    clang_analyzer_eval(((POD){1, 42}).y == 42); // expected-warning{{TRUE}}
101    clang_analyzer_eval(((HasDtor){1, 42}).y == 42); // expected-warning{{TRUE}}
102
103#if __cplusplus >= 201103L
104    clang_analyzer_eval(((HasCtor){1, 42}).y == 42); // expected-warning{{TRUE}}
105
106    // FIXME: should be TRUE, but we don't inline the constructors of
107    // temporaries because we can't model their destructors yet.
108    clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}}
109#endif
110  }
111}
112
113namespace destructors {
114  void testPR16664andPR18159Crash() {
115    struct Dtor {
116      ~Dtor();
117    };
118    extern bool coin();
119    extern bool check(const Dtor &);
120
121    // Regression test: we used to assert here when tmp dtors are enabled.
122    // PR16664 and PR18159
123    if (coin() && (coin() || coin() || check(Dtor()))) {
124      Dtor();
125    }
126  }
127
128#ifdef TEMPORARY_DTORS
129  struct NoReturnDtor {
130    ~NoReturnDtor() __attribute__((noreturn));
131  };
132
133  void noReturnTemp(int *x) {
134    if (! x) NoReturnDtor();
135    *x = 47; // no warning
136  }
137
138  void noReturnInline(int **x) {
139    NoReturnDtor();
140  }
141
142  void callNoReturn() {
143    int *x;
144    noReturnInline(&x);
145    *x = 47; // no warning
146  }
147
148  extern bool check(const NoReturnDtor &);
149
150  void testConsistencyIf(int i) {
151    if (i != 5)
152      return;
153    if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) {
154      clang_analyzer_eval(true); // no warning, unreachable code
155    }
156  }
157
158  void testConsistencyTernary(int i) {
159    (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
160
161    clang_analyzer_eval(true);  // expected-warning{{TRUE}}
162
163    if (i != 5)
164      return;
165
166    (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
167
168    clang_analyzer_eval(true); // no warning, unreachable code
169  }
170
171  // Regression test: we used to assert here.
172  // PR16664 and PR18159
173  void testConsistencyNested(int i) {
174    extern bool compute(bool);
175
176    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
177      clang_analyzer_eval(true);  // expected-warning{{TRUE}}
178
179    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
180      clang_analyzer_eval(true);  // expected-warning{{TRUE}}
181
182    if (i != 5)
183      return;
184
185    if (compute(i == 5 &&
186                (i == 4 || compute(true) ||
187                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
188        i != 4) {
189      clang_analyzer_eval(true);  // expected-warning{{TRUE}}
190    }
191
192    if (compute(i == 5 &&
193                (i == 4 || i == 4 ||
194                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
195        i != 4) {
196      // FIXME: This shouldn't cause a warning.
197      clang_analyzer_eval(true);  // expected-warning{{TRUE}}
198    }
199  }
200
201  // PR16664 and PR18159
202  void testConsistencyNestedSimple(bool value) {
203    if (value) {
204      if (!value || check(NoReturnDtor())) {
205        clang_analyzer_eval(true); // no warning, unreachable code
206      }
207    }
208  }
209
210  // PR16664 and PR18159
211  void testConsistencyNestedComplex(bool value) {
212    if (value) {
213      if (!value || !value || check(NoReturnDtor())) {
214        // FIXME: This shouldn't cause a warning.
215        clang_analyzer_eval(true); // expected-warning{{TRUE}}
216      }
217    }
218  }
219
220  // PR16664 and PR18159
221  void testConsistencyNestedWarning(bool value) {
222    if (value) {
223      if (!value || value || check(NoReturnDtor())) {
224        clang_analyzer_eval(true); // expected-warning{{TRUE}}
225      }
226    }
227  }
228
229  void testBinaryOperatorShortcut(bool value) {
230    if (value) {
231      if (false && false && check(NoReturnDtor()) && true) {
232        clang_analyzer_eval(true);
233      }
234    }
235  }
236
237#endif // TEMPORARY_DTORS
238}
239
240void testStaticMaterializeTemporaryExpr() {
241  static const Trivial &ref = getTrivial();
242  clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
243
244  static const Trivial &directRef = Trivial(42);
245  clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
246
247#if __has_feature(cxx_thread_local)
248  thread_local static const Trivial &threadRef = getTrivial();
249  clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
250
251  thread_local static const Trivial &threadDirectRef = Trivial(42);
252  clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
253#endif
254}
255
256namespace PR16629 {
257  struct A {
258    explicit A(int* p_) : p(p_) {}
259    int* p;
260  };
261
262  extern void escape(const A*[]);
263  extern void check(int);
264
265  void callEscape(const A& a) {
266    const A* args[] = { &a };
267    escape(args);
268  }
269
270  void testNoWarning() {
271    int x;
272    callEscape(A(&x));
273    check(x); // Analyzer used to give a "x is uninitialized warning" here
274  }
275
276  void set(const A*a[]) {
277    *a[0]->p = 47;
278  }
279
280  void callSet(const A& a) {
281    const A* args[] = { &a };
282    set(args);
283  }
284
285  void testConsistency() {
286    int x;
287    callSet(A(&x));
288    clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
289  }
290}
291