Clang Project

clang_source_code/test/Analysis/array-struct-region.cpp
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
20void clang_analyzer_eval(int);
21
22struct 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
37const struct S *operator -(const struct S &s) { return &s; }
38bool operator ~(const struct S &s) { return (&s) != &s; }
39#endif
40
41
42#ifdef INLINE
43struct S getS() {
44  struct S s = { 42 };
45  return s;
46}
47#else
48struct S getS();
49#endif
50
51
52void 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
75void 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
92int getConstrainedField(struct S s) {
93  if (s.field != 42) return 42;
94  return s.field;
95}
96
97int getAssignedField(struct S s) {
98  s.field = 42;
99  return s.field;
100}
101
102void testArgument() {
103  clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
104  clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
105}
106
107void 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
129void 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
146int getConstrainedFieldRef(const S &s) {
147  if (s.field != 42) return 42;
148  return s.field;
149}
150
151bool checkThis(const S &s) {
152  return s.getThis() == &s;
153}
154
155bool checkThisOp(const S &s) {
156  return +s == &s;
157}
158
159bool checkThisStaticOp(const S &s) {
160  return -s == &s;
161}
162
163void 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
171int getConstrainedFieldOp(S s) {
172  if (*s != 42) return 42;
173  return *s;
174}
175
176int getConstrainedFieldRefOp(const S &s) {
177  if (*s != 42) return 42;
178  return *s;
179}
180
181void 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
190namespace 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
214namespace aggregate_inheritance_cxx17 {
215struct A {
216  int x;
217};
218
219struct B {
220  int y;
221};
222
223struct C: B {
224  int z;
225};
226
227struct D: A, C {
228  int w;
229};
230
231void 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
241namespace flex_array_inheritance_cxx17 {
242struct A {
243  int flexible_array[];
244};
245
246struct B {
247  long cookie;
248};
249
250struct C : B {
251  A a;
252};
253
254void foo() {
255  C c{}; // no-crash
256}
257} // namespace flex_array_inheritance_cxx17
258#endif
259