1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
2 // RUN: -analyzer-checker=debug.ExprInspection -verify\
3 // RUN: -Wno-tautological-compare\
4 // RUN: -x c %s
5 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
6 // RUN: -analyzer-checker=debug.ExprInspection -verify\
7 // RUN: -Wno-tautological-compare\
8 // RUN: -x c++ -std=c++14 %s
9 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
10 // RUN: -analyzer-checker=debug.ExprInspection -verify\
11 // RUN: -Wno-tautological-compare\
12 // RUN: -x c++ -std=c++17 %s
13 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
14 // RUN: -analyzer-checker=debug.ExprInspection -verify\
15 // RUN: -Wno-tautological-compare\
16 // RUN: -DINLINE -x c %s
17 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
18 // RUN: -analyzer-checker=debug.ExprInspection -verify\
19 // RUN: -Wno-tautological-compare\
20 // RUN: -DINLINE -x c++ -std=c++14 %s
21 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
22 // RUN: -analyzer-checker=debug.ExprInspection -verify\
23 // RUN: -Wno-tautological-compare\
24 // RUN: -DINLINE -x c++ -std=c++17 %s
25
26 void clang_analyzer_eval(int);
27
28 struct S {
29 int field;
30
31 #if __cplusplus
getThisS32 const struct S *getThis() const { return this; }
operator +S33 const struct S *operator +() const { return this; }
34
checkS35 bool check() const { return this == this; }
operator !S36 bool operator !() const { return this != this; }
37
operator *S38 int operator *() const { return field; }
39 #endif
40 };
41
42 #if __cplusplus
operator -(const struct S & s)43 const struct S *operator -(const struct S &s) { return &s; }
operator ~(const struct S & s)44 bool operator ~(const struct S &s) { return (&s) != &s; }
45 #endif
46
47
48 #ifdef INLINE
getS()49 struct S getS() {
50 struct S s = { 42 };
51 return s;
52 }
53 #else
54 struct S getS();
55 #endif
56
57
testAssignment()58 void testAssignment() {
59 struct S s = getS();
60
61 if (s.field != 42) return;
62 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
63
64 s.field = 0;
65 clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}}
66
67 #if __cplusplus
68 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
69 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
70 clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}}
71
72 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
73 clang_analyzer_eval(!s); // expected-warning{{FALSE}}
74 clang_analyzer_eval(~s); // expected-warning{{FALSE}}
75
76 clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}}
77 #endif
78 }
79
80
testImmediateUse()81 void testImmediateUse() {
82 int x = getS().field;
83
84 if (x != 42) return;
85 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
86
87 #if __cplusplus
88 clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}}
89 clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}}
90 clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}}
91
92 clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}}
93 clang_analyzer_eval(!getS()); // expected-warning{{FALSE}}
94 clang_analyzer_eval(~getS()); // expected-warning{{FALSE}}
95 #endif
96 }
97
getConstrainedField(struct S s)98 int getConstrainedField(struct S s) {
99 if (s.field != 42) return 42;
100 return s.field;
101 }
102
getAssignedField(struct S s)103 int getAssignedField(struct S s) {
104 s.field = 42;
105 return s.field;
106 }
107
testArgument()108 void testArgument() {
109 clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
110 clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
111 }
112
testImmediateUseParens()113 void testImmediateUseParens() {
114 int x = ((getS())).field;
115
116 if (x != 42) return;
117 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
118
119 clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}}
120 clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}}
121
122 #if __cplusplus
123 clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}}
124 clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}}
125 clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}}
126 #endif
127 }
128
129
130 //--------------------
131 // C++-only tests
132 //--------------------
133
134 #if __cplusplus
testReferenceAssignment()135 void testReferenceAssignment() {
136 const S &s = getS();
137
138 if (s.field != 42) return;
139 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
140
141 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
142 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
143
144 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
145 clang_analyzer_eval(!s); // expected-warning{{FALSE}}
146 clang_analyzer_eval(~s); // expected-warning{{FALSE}}
147
148 clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}}
149 }
150
151
getConstrainedFieldRef(const S & s)152 int getConstrainedFieldRef(const S &s) {
153 if (s.field != 42) return 42;
154 return s.field;
155 }
156
checkThis(const S & s)157 bool checkThis(const S &s) {
158 return s.getThis() == &s;
159 }
160
checkThisOp(const S & s)161 bool checkThisOp(const S &s) {
162 return +s == &s;
163 }
164
checkThisStaticOp(const S & s)165 bool checkThisStaticOp(const S &s) {
166 return -s == &s;
167 }
168
testReferenceArgument()169 void testReferenceArgument() {
170 clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}}
171 clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}}
172 clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}}
173 clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}}
174 }
175
176
getConstrainedFieldOp(S s)177 int getConstrainedFieldOp(S s) {
178 if (*s != 42) return 42;
179 return *s;
180 }
181
getConstrainedFieldRefOp(const S & s)182 int getConstrainedFieldRefOp(const S &s) {
183 if (*s != 42) return 42;
184 return *s;
185 }
186
testImmediateUseOp()187 void testImmediateUseOp() {
188 int x = *getS();
189 if (x != 42) return;
190 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
191
192 clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}}
193 clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}}
194 }
195
196 namespace EmptyClass {
197 struct Base {
198 int& x;
199
BaseEmptyClass::Base200 Base(int& x) : x(x) {}
201 };
202
203 struct Derived : public Base {
DerivedEmptyClass::Derived204 Derived(int& x) : Base(x) {}
205
operator =EmptyClass::Derived206 void operator=(int a) { x = a; }
207 };
208
ref(int & a)209 Derived ref(int& a) { return Derived(a); }
210
211 // There used to be a warning here, because analyzer treated Derived as empty.
test()212 int test() {
213 int a;
214 ref(a) = 42;
215 return a; // no warning
216 }
217 }
218
219 #if __cplusplus >= 201703L
220 namespace aggregate_inheritance_cxx17 {
221 struct A {
222 int x;
223 };
224
225 struct B {
226 int y;
227 };
228
229 struct C: B {
230 int z;
231 };
232
233 struct D: A, C {
234 int w;
235 };
236
foo()237 void foo() {
238 D d{1, 2, 3, 4};
239 clang_analyzer_eval(d.x == 1); // expected-warning{{TRUE}}
240 clang_analyzer_eval(d.y == 2); // expected-warning{{TRUE}}
241 clang_analyzer_eval(d.z == 3); // expected-warning{{TRUE}}
242 clang_analyzer_eval(d.w == 4); // expected-warning{{TRUE}}
243 }
244 } // namespace aggregate_inheritance_cxx17
245 #endif
246
247 namespace flex_array_inheritance_cxx17 {
248 struct A {
249 int flexible_array[];
250 };
251
252 struct B {
253 long cookie;
254 };
255
256 struct C : B {
257 A a;
258 };
259
foo()260 void foo() {
261 C c{}; // no-crash
262 }
263 } // namespace flex_array_inheritance_cxx17
264 #endif
265