temporaries.cpp revision 651f13cea278ec967336033dd032faef0e9fc2ec
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#ifndef TEMPORARY_DTORS
122    // FIXME: Don't assert here when tmp dtors are enabled.
123    // PR16664 and PR18159
124    if (coin() && (coin() || coin() || check(Dtor()))) {
125      Dtor();
126    }
127#endif
128  }
129
130#ifdef TEMPORARY_DTORS
131  struct NoReturnDtor {
132    ~NoReturnDtor() __attribute__((noreturn));
133  };
134
135  void noReturnTemp(int *x) {
136    if (! x) NoReturnDtor();
137    *x = 47; // no warning
138  }
139
140  void noReturnInline(int **x) {
141    NoReturnDtor();
142  }
143
144  void callNoReturn() {
145    int *x;
146    noReturnInline(&x);
147    *x = 47; // no warning
148  }
149
150  extern bool check(const NoReturnDtor &);
151
152  void testConsistencyIf(int i) {
153    if (i != 5)
154      return;
155    if (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) {
156      clang_analyzer_eval(true); // no warning, unreachable code
157    }
158  }
159
160  void testConsistencyTernary(int i) {
161    (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
162
163    clang_analyzer_eval(true);  // expected-warning{{TRUE}}
164
165    if (i != 5)
166      return;
167
168    (i == 5 && (i == 4 || check(NoReturnDtor()) || i == 5)) ? 1 : 0;
169
170    clang_analyzer_eval(true); // no warning, unreachable code
171  }
172
173/*
174  // PR16664 and PR18159
175  FIXME: Don't assert here.
176  void testConsistencyNested(int i) {
177    extern bool compute(bool);
178
179    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
180      clang_analyzer_eval(true); // expected TRUE
181
182    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
183      clang_analyzer_eval(true);  // expected TRUE
184
185    if (i != 5)
186      return;
187
188    if (compute(i == 5 &&
189                (i == 4 || compute(true) ||
190                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
191        i != 4) {
192      clang_analyzer_eval(true); // expected TRUE
193    }
194
195    FIXME: This shouldn't cause a warning.
196    if (compute(i == 5 &&
197                (i == 4 || i == 4 ||
198                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
199        i != 4) {
200      clang_analyzer_eval(true); // no warning, unreachable code
201    }
202  }*/
203
204  // PR16664 and PR18159
205  void testConsistencyNestedSimple(bool value) {
206    if (value) {
207      if (!value || check(NoReturnDtor())) {
208        clang_analyzer_eval(true); // no warning, unreachable code
209      }
210    }
211  }
212
213  // PR16664 and PR18159
214  void testConsistencyNestedComplex(bool value) {
215    if (value) {
216      if (!value || !value || check(NoReturnDtor())) {
217        // FIXME: This shouldn't cause a warning.
218        clang_analyzer_eval(true); // expected-warning{{TRUE}}
219      }
220    }
221  }
222
223  // PR16664 and PR18159
224  void testConsistencyNestedWarning(bool value) {
225    if (value) {
226      if (!value || value || check(NoReturnDtor())) {
227        clang_analyzer_eval(true); // expected-warning{{TRUE}}
228      }
229    }
230  }
231
232#endif // TEMPORARY_DTORS
233}
234
235void testStaticMaterializeTemporaryExpr() {
236  static const Trivial &ref = getTrivial();
237  clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
238
239  static const Trivial &directRef = Trivial(42);
240  clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
241
242#if __has_feature(cxx_thread_local)
243  thread_local static const Trivial &threadRef = getTrivial();
244  clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
245
246  thread_local static const Trivial &threadDirectRef = Trivial(42);
247  clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
248#endif
249}
250
251namespace PR16629 {
252  struct A {
253    explicit A(int* p_) : p(p_) {}
254    int* p;
255  };
256
257  extern void escape(const A*[]);
258  extern void check(int);
259
260  void callEscape(const A& a) {
261    const A* args[] = { &a };
262    escape(args);
263  }
264
265  void testNoWarning() {
266    int x;
267    callEscape(A(&x));
268    check(x); // Analyzer used to give a "x is uninitialized warning" here
269  }
270
271  void set(const A*a[]) {
272    *a[0]->p = 47;
273  }
274
275  void callSet(const A& a) {
276    const A* args[] = { &a };
277    set(args);
278  }
279
280  void testConsistency() {
281    int x;
282    callSet(A(&x));
283    clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
284  }
285}
286