1 // RUN: %clang %s -std=c++17 -Xclang -verify --analyze \
2 // RUN: -Xclang -analyzer-checker=core \
3 // RUN: -Xclang -analyzer-checker=debug.ExprInspection \
4 // RUN: -Xclang -analyzer-checker=core,alpha.core.StdVariant
5
6 #include "Inputs/system-header-simulator-cxx.h"
7
8 class Foo{};
9
10 void clang_analyzer_warnIfReached();
11 void clang_analyzer_eval(int);
12
13 //helper functions
changeVariantType(std::variant<int,char> & v)14 void changeVariantType(std::variant<int, char> &v) {
15 v = 25;
16 }
17
18 void changesToInt(std::variant<int, char> &v);
19 void changesToInt(std::variant<int, char> *v);
20
21 void cannotChangePtr(const std::variant<int, char> &v);
22 void cannotChangePtr(const std::variant<int, char> *v);
23
24 char getUnknownChar();
25
swap(std::variant<int,char> & v1,std::variant<int,char> & v2)26 void swap(std::variant<int, char> &v1, std::variant<int, char> &v2) {
27 std::variant<int, char> tmp = v1;
28 v1 = v2;
29 v2 = tmp;
30 }
31
cantDo(const std::variant<int,char> & v)32 void cantDo(const std::variant<int, char>& v) {
33 std::variant<int, char> vtmp = v;
34 vtmp = 5;
35 int a = std::get<int> (vtmp);
36 (void) a;
37 }
38
changeVariantPtr(std::variant<int,char> * v)39 void changeVariantPtr(std::variant<int, char> *v) {
40 *v = 'c';
41 }
42
43 using var_t = std::variant<int, char>;
44 using var_tt = var_t;
45 using int_t = int;
46 using char_t = char;
47
48 // A quick sanity check to see that std::variant's std::get
49 // is not being confused with std::pairs std::get.
wontConfuseStdGets()50 void wontConfuseStdGets() {
51 std::pair<int, char> p{15, '1'};
52 int a = std::get<int>(p);
53 char c = std::get<char>(p);
54 (void)a;
55 (void)c;
56 }
57
58 //----------------------------------------------------------------------------//
59 // std::get
60 //----------------------------------------------------------------------------//
stdGetType()61 void stdGetType() {
62 std::variant<int, char> v = 25;
63 int a = std::get<int>(v);
64 char c = std::get<char>(v); // expected-warning {{std::variant 'v' held an 'int', not a 'char'}}
65 (void)a;
66 (void)c;
67 }
68
stdGetPointer()69 void stdGetPointer() {
70 int *p = new int;
71 std::variant<int*, char> v = p;
72 int *a = std::get<int*>(v);
73 char c = std::get<char>(v); // expected-warning {{std::variant 'v' held an 'int *', not a 'char'}}
74 (void)a;
75 (void)c;
76 delete p;
77 }
78
stdGetObject()79 void stdGetObject() {
80 std::variant<int, char, Foo> v = Foo{};
81 Foo f = std::get<Foo>(v);
82 int i = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'Foo', not an 'int'}}
83 (void)i;
84 }
85
stdGetPointerAndPointee()86 void stdGetPointerAndPointee() {
87 int a = 5;
88 std::variant<int, int*> v = &a;
89 int *b = std::get<int*>(v);
90 int c = std::get<int>(v); // expected-warning {{std::variant 'v' held an 'int *', not an 'int'}}
91 (void)c;
92 (void)b;
93 }
94
variantHoldingVariant()95 void variantHoldingVariant() {
96 std::variant<std::variant<int, char>, std::variant<char, int>> v = std::variant<int,char>(25);
97 std::variant<int, char> v1 = std::get<std::variant<int,char>>(v);
98 std::variant<char, int> v2 = std::get<std::variant<char,int>>(v); // expected-warning {{std::variant 'v' held a 'std::variant<int, char>', not a 'class std::variant<char, int>'}}
99 }
100
101 //----------------------------------------------------------------------------//
102 // Constructors and assignments
103 //----------------------------------------------------------------------------//
copyConstructor()104 void copyConstructor() {
105 std::variant<int, char> v = 25;
106 std::variant<int, char> t(v);
107 int a = std::get<int> (t);
108 char c = std::get<char> (t); // expected-warning {{std::variant 't' held an 'int', not a 'char'}}
109 (void)a;
110 (void)c;
111 }
112
copyAssignmentOperator()113 void copyAssignmentOperator() {
114 std::variant<int, char> v = 25;
115 std::variant<int, char> t = 'c';
116 t = v;
117 int a = std::get<int> (t);
118 char c = std::get<char> (t); // expected-warning {{std::variant 't' held an 'int', not a 'char'}}
119 (void)a;
120 (void)c;
121 }
122
assignmentOperator()123 void assignmentOperator() {
124 std::variant<int, char> v = 25;
125 int a = std::get<int> (v);
126 (void)a;
127 v = 'c';
128 char c = std::get<char>(v);
129 a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
130 (void)a;
131 (void)c;
132 }
133
typeChangeThreeTimes()134 void typeChangeThreeTimes() {
135 std::variant<int, char, float> v = 25;
136 int a = std::get<int> (v);
137 (void)a;
138 v = 'c';
139 char c = std::get<char>(v);
140 v = 25;
141 a = std::get<int>(v);
142 (void)a;
143 v = 1.25f;
144 float f = std::get<float>(v);
145 a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'float', not an 'int'}}
146 (void)a;
147 (void)c;
148 (void)f;
149 }
150
defaultConstructor()151 void defaultConstructor() {
152 std::variant<int, char> v;
153 int i = std::get<int>(v);
154 char c = std::get<char>(v); // expected-warning {{std::variant 'v' held an 'int', not a 'char'}}
155 (void)i;
156 (void)c;
157 }
158
159 // Verify that we handle temporary objects correctly
temporaryObjectsConstructor()160 void temporaryObjectsConstructor() {
161 std::variant<int, char> v(std::variant<int, char>('c'));
162 char c = std::get<char>(v);
163 int a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
164 (void)a;
165 (void)c;
166 }
167
temporaryObjectsAssignment()168 void temporaryObjectsAssignment() {
169 std::variant<int, char> v = std::variant<int, char>('c');
170 char c = std::get<char>(v);
171 int a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
172 (void)a;
173 (void)c;
174 }
175
176 // Verify that we handle pointer types correctly
pointerTypeHeld()177 void pointerTypeHeld() {
178 int *p = new int;
179 std::variant<int*, char> v = p;
180 int *a = std::get<int*>(v);
181 char c = std::get<char>(v); // expected-warning {{std::variant 'v' held an 'int *', not a 'char'}}
182 (void)a;
183 (void)c;
184 delete p;
185 }
186
187 std::variant<int, char> get_unknown_variant();
188 // Verify that the copy constructor is handles properly when the std::variant
189 // has no previously activated type and we copy an object of unknown value in it.
copyFromUnknownVariant()190 void copyFromUnknownVariant() {
191 std::variant<int, char> u = get_unknown_variant();
192 std::variant<int, char> v(u);
193 int a = std::get<int>(v); // no-waring
194 char c = std::get<char>(v); // no-warning
195 (void)a;
196 (void)c;
197 }
198
199 // Verify that the copy constructor is handles properly when the std::variant
200 // has previously activated type and we copy an object of unknown value in it.
copyFromUnknownVariantBef()201 void copyFromUnknownVariantBef() {
202 std::variant<int, char> v = 25;
203 std::variant<int, char> u = get_unknown_variant();
204 v = u;
205 int a = std::get<int>(v); // no-waring
206 char c = std::get<char>(v); // no-warning
207 (void)a;
208 (void)c;
209 }
210
211 //----------------------------------------------------------------------------//
212 // typedef
213 //----------------------------------------------------------------------------//
214
typefdefedVariant()215 void typefdefedVariant() {
216 var_t v = 25;
217 int a = std::get<int>(v);
218 char c = std::get<char>(v); // expected-warning {{std::variant 'v' held an 'int', not a 'char'}}
219 (void)a;
220 (void)c;
221 }
222
typedefedTypedfefedVariant()223 void typedefedTypedfefedVariant() {
224 var_tt v = 25;
225 int a = std::get<int>(v);
226 char c = std::get<char>(v); // expected-warning {{std::variant 'v' held an 'int', not a 'char'}}
227 (void)a;
228 (void)c;
229 }
230
typedefedGet()231 void typedefedGet() {
232 std::variant<char, int> v = 25;
233 int a = std::get<int_t>(v);
234 char c = std::get<char_t>(v); // expected-warning {{std::variant 'v' held an 'int', not a 'char'}}
235 (void)a;
236 (void)c;
237 }
238
typedefedPack()239 void typedefedPack() {
240 std::variant<int_t, char_t> v = 25;
241 int a = std::get<int>(v);
242 char c = std::get<char>(v); // expected-warning {{std::variant 'v' held an 'int', not a 'char'}}
243 (void)a;
244 (void)c;
245 }
246
fromVariable()247 void fromVariable() {
248 char o = 'c';
249 std::variant<int, char> v(o);
250 char c = std::get<char>(v);
251 int a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
252 (void)a;
253 (void)c;
254 }
255
unknowValueButKnownType()256 void unknowValueButKnownType() {
257 char o = getUnknownChar();
258 std::variant<int, char> v(o);
259 char c = std::get<char>(v);
260 int a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
261 (void)a;
262 (void)c;
263 }
264
createPointer()265 void createPointer() {
266 std::variant<int, char> *v = new std::variant<int, char>(15);
267 int a = std::get<int>(*v);
268 char c = std::get<char>(*v); // expected-warning {{std::variant held an 'int', not a 'char'}}
269 (void)a;
270 (void)c;
271 delete v;
272 }
273
274 //----------------------------------------------------------------------------//
275 // Passing std::variants to functions
276 //----------------------------------------------------------------------------//
277
278 // Verifying that we are not invalidating the memory region of a variant if
279 // a non inlined or inlined function takes it as a constant reference or pointer
constNonInlineRef()280 void constNonInlineRef() {
281 std::variant<int, char> v = 'c';
282 cannotChangePtr(v);
283 char c = std::get<char>(v);
284 int a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
285 (void)a;
286 (void)c;
287 }
288
contNonInlinePtr()289 void contNonInlinePtr() {
290 std::variant<int, char> v = 'c';
291 cannotChangePtr(&v);
292 char c = std::get<char>(v);
293 int a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
294 (void)a;
295 (void)c;
296 }
297
copyInAFunction()298 void copyInAFunction() {
299 std::variant<int, char> v = 'c';
300 cantDo(v);
301 char c = std::get<char>(v);
302 int a = std::get<int>(v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
303 (void)a;
304 (void)c;
305
306 }
307
308 // Verifying that we can keep track of the type stored in std::variant when
309 // it is passed to an inlined function as a reference or pointer
changeThruPointers()310 void changeThruPointers() {
311 std::variant<int, char> v = 15;
312 changeVariantPtr(&v);
313 char c = std::get<char> (v);
314 int a = std::get<int> (v); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
315 (void)a;
316 (void)c;
317 }
318
functionCallWithCopyAssignment()319 void functionCallWithCopyAssignment() {
320 var_t v1 = 15;
321 var_t v2 = 'c';
322 swap(v1, v2);
323 int a = std::get<int> (v2);
324 (void)a;
325 char c = std::get<char> (v1);
326 a = std::get<int> (v1); // expected-warning {{std::variant 'v1' held a 'char', not an 'int'}}
327 (void)a;
328 (void)c;
329 }
330
inlineFunctionCall()331 void inlineFunctionCall() {
332 std::variant<int, char> v = 'c';
333 changeVariantType(v);
334 int a = std::get<int> (v);
335 char c = std::get<char> (v); // expected-warning {{std::variant 'v' held an 'int', not a 'char'}}
336 (void)a;
337 (void)c;
338 }
339
340 // Verifying that we invalidate the mem region of std::variant when it is
341 // passed as a non const reference or a pointer to a non inlined function.
nonInlineFunctionCall()342 void nonInlineFunctionCall() {
343 std::variant<int, char> v = 'c';
344 changesToInt(v);
345 int a = std::get<int> (v); // no-waring
346 char c = std::get<char> (v); // no-warning
347 (void)a;
348 (void)c;
349 }
350
nonInlineFunctionCallPtr()351 void nonInlineFunctionCallPtr() {
352 std::variant<int, char> v = 'c';
353 changesToInt(&v);
354 int a = std::get<int> (v); // no-warning
355 char c = std::get<char> (v); // no-warning
356 (void)a;
357 (void)c;
358 }