xref: /minix3/external/bsd/llvm/dist/clang/test/Analysis/temporaries.cpp (revision 0b98e8aad89f2bd4ba80b523d73cf29e9dd82ce1)
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 
5 extern bool clang_analyzer_eval(bool);
6 
7 struct Trivial {
8   Trivial(int x) : value(x) {}
9   int value;
10 };
11 
12 struct NonTrivial : public Trivial {
13   NonTrivial(int x) : Trivial(x) {}
14   ~NonTrivial();
15 };
16 
17 
18 Trivial getTrivial() {
19   return Trivial(42); // no-warning
20 }
21 
22 const 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 
27 NonTrivial getNonTrivial() {
28   return NonTrivial(42); // no-warning
29 }
30 
31 const NonTrivial &getNonTrivialRef() {
32   return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}}
33 }
34 
35 namespace 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 
67 namespace 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 
81 namespace 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 
113 namespace 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 
199 void 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 
215 namespace 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