temporaries.cpp revision dd9e9cec6f863afa15dd91b34fbf15c66c678c02
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 crash here when tmp dtros 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/*
175  // PR16664 and PR18159
176  FIXME: Don't crash here.
177  void testConsistencyNested(int i) {
178    extern bool compute(bool);
179
180    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
181      clang_analyzer_eval(true); // expected TRUE
182
183    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
184      clang_analyzer_eval(true);  // expected TRUE
185
186    if (i != 5)
187      return;
188
189    if (compute(i == 5 &&
190                (i == 4 || compute(true) ||
191                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
192        i != 4) {
193      clang_analyzer_eval(true); // expected TRUE
194    }
195
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#endif // TEMPORARY_DTORS
205}
206
207void testStaticMaterializeTemporaryExpr() {
208  static const Trivial &ref = getTrivial();
209  clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
210
211  static const Trivial &directRef = Trivial(42);
212  clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
213
214#if __has_feature(cxx_thread_local)
215  thread_local static const Trivial &threadRef = getTrivial();
216  clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
217
218  thread_local static const Trivial &threadDirectRef = Trivial(42);
219  clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
220#endif
221}
222
223namespace PR16629 {
224  struct A {
225    explicit A(int* p_) : p(p_) {}
226    int* p;
227  };
228
229  extern void escape(const A*[]);
230  extern void check(int);
231
232  void callEscape(const A& a) {
233    const A* args[] = { &a };
234    escape(args);
235  }
236
237  void testNoWarning() {
238    int x;
239    callEscape(A(&x));
240    check(x); // Analyzer used to give a "x is uninitialized warning" here
241  }
242
243  void set(const A*a[]) {
244    *a[0]->p = 47;
245  }
246
247  void callSet(const A& a) {
248    const A* args[] = { &a };
249    set(args);
250  }
251
252  void testConsistency() {
253    int x;
254    callSet(A(&x));
255    clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
256  }
257}
258