temporaries.cpp revision 95ab9e306f4deefeabd89ea61987f4a8d67e0890
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 -verify -w -analyzer-config cfg-temporary-dtors=true %s -DTEMPORARY_DTORS
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 testPR16664Crash() {
115    struct Dtor {
116      ~Dtor();
117    };
118    extern bool coin();
119    extern bool check(const Dtor &);
120
121    // Don't crash here.
122    if (coin() && (coin() || coin() || check(Dtor()))) {
123      Dtor();
124    }
125  }
126
127#ifdef TEMPORARY_DTORS
128  struct NoReturnDtor {
129    ~NoReturnDtor() __attribute__((noreturn));
130  };
131
132  void noReturnTemp(int *x) {
133    if (! x) NoReturnDtor();
134    *x = 47; // no warning
135  }
136
137  void noReturnInline(int **x) {
138    NoReturnDtor();
139  }
140
141  void callNoReturn() {
142    int *x;
143    noReturnInline(&x);
144    *x = 47; // no warning
145  }
146
147  extern bool check(const NoReturnDtor &);
148
149  void testConsistencyIf(int i) {
150    if (i == 5 && (i == 4 || i == 5 || check(NoReturnDtor())))
151      clang_analyzer_eval(true); // expected-warning{{TRUE}}
152
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  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)
180      return;
181
182    if (compute(i == 5 &&
183                (i == 4 || compute(true) ||
184                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
185        i != 4) {
186      clang_analyzer_eval(true); // expected-warning{{TRUE}}
187    }
188
189    if (compute(i == 5 &&
190                (i == 4 || i == 4 ||
191                 compute(i == 5 && (i == 4 || check(NoReturnDtor()))))) ||
192        i != 4) {
193      clang_analyzer_eval(true); // no warning, unreachable code
194    }
195  }
196#endif // TEMPORARY_DTORS
197}
198
199void testStaticMaterializeTemporaryExpr() {
200  static const Trivial &ref = getTrivial();
201  clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
202
203  static const Trivial &directRef = Trivial(42);
204  clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
205
206#if __has_feature(cxx_thread_local)
207  thread_local static const Trivial &threadRef = getTrivial();
208  clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
209
210  thread_local static const Trivial &threadDirectRef = Trivial(42);
211  clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
212#endif
213}
214
215namespace PR16629 {
216  struct A {
217    explicit A(int* p_) : p(p_) {}
218    int* p;
219  };
220
221  extern void escape(const A*[]);
222  extern void check(int);
223
224  void callEscape(const A& a) {
225    const A* args[] = { &a };
226    escape(args);
227  }
228
229  void testNoWarning() {
230    int x;
231    callEscape(A(&x));
232    check(x); // Analyzer used to give a "x is uninitialized warning" here
233  }
234
235  void set(const A*a[]) {
236    *a[0]->p = 47;
237  }
238
239  void callSet(const A& a) {
240    const A* args[] = { &a };
241    set(args);
242  }
243
244  void testConsistency() {
245    int x;
246    callSet(A(&x));
247    clang_analyzer_eval(x == 47); // expected-warning{{TRUE}}
248  }
249}
250