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