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