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
6 #include "Inputs/system-header-simulator-cxx.h"
10 void clang_analyzer_warnIfReached();
11 void clang_analyzer_eval(int);
14 void changeVariantType(std::variant
<int, char> &v
) {
18 void changesToInt(std::variant
<int, char> &v
);
19 void changesToInt(std::variant
<int, char> *v
);
21 void cannotChangePtr(const std::variant
<int, char> &v
);
22 void cannotChangePtr(const std::variant
<int, char> *v
);
24 char getUnknownChar();
26 void swap(std::variant
<int, char> &v1
, std::variant
<int, char> &v2
) {
27 std::variant
<int, char> tmp
= v1
;
32 void cantDo(const std::variant
<int, char>& v
) {
33 std::variant
<int, char> vtmp
= v
;
35 int a
= std::get
<int> (vtmp
);
39 void changeVariantPtr(std::variant
<int, char> *v
) {
43 using var_t
= std::variant
<int, char>;
48 // A quick sanity check to see that std::variant's std::get
49 // is not being confused with std::pairs std::get.
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
);
58 //----------------------------------------------------------------------------//
60 //----------------------------------------------------------------------------//
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'}}
69 void stdGetPointer() {
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'}}
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'}}
86 void stdGetPointerAndPointee() {
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'}}
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>'}}
101 //----------------------------------------------------------------------------//
102 // Constructors and assignments
103 //----------------------------------------------------------------------------//
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'}}
113 void copyAssignmentOperator() {
114 std::variant
<int, char> v
= 25;
115 std::variant
<int, char> t
= 'c';
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'}}
123 void assignmentOperator() {
124 std::variant
<int, char> v
= 25;
125 int a
= std::get
<int> (v
);
128 char c
= std::get
<char>(v
);
129 a
= std::get
<int>(v
); // expected-warning {{std::variant 'v' held a 'char', not an 'int'}}
134 void typeChangeThreeTimes() {
135 std::variant
<int, char, float> v
= 25;
136 int a
= std::get
<int> (v
);
139 char c
= std::get
<char>(v
);
141 a
= std::get
<int>(v
);
144 float f
= std::get
<float>(v
);
145 a
= std::get
<int>(v
); // expected-warning {{std::variant 'v' held a 'float', not an 'int'}}
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'}}
159 // Verify that we handle temporary objects correctly
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'}}
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'}}
176 // Verify that we handle pointer types correctly
177 void pointerTypeHeld() {
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'}}
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.
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
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.
201 void copyFromUnknownVariantBef() {
202 std::variant
<int, char> v
= 25;
203 std::variant
<int, char> u
= get_unknown_variant();
205 int a
= std::get
<int>(v
); // no-waring
206 char c
= std::get
<char>(v
); // no-warning
211 //----------------------------------------------------------------------------//
213 //----------------------------------------------------------------------------//
215 void typefdefedVariant() {
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'}}
223 void typedefedTypedfefedVariant() {
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'}}
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'}}
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'}}
247 void fromVariable() {
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'}}
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'}}
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'}}
274 //----------------------------------------------------------------------------//
275 // Passing std::variants to functions
276 //----------------------------------------------------------------------------//
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
280 void constNonInlineRef() {
281 std::variant
<int, char> v
= 'c';
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'}}
289 void contNonInlinePtr() {
290 std::variant
<int, char> v
= 'c';
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'}}
298 void copyInAFunction() {
299 std::variant
<int, char> v
= 'c';
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'}}
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
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'}}
319 void functionCallWithCopyAssignment() {
323 int a
= std::get
<int> (v2
);
325 char c
= std::get
<char> (v1
);
326 a
= std::get
<int> (v1
); // expected-warning {{std::variant 'v1' held a 'char', not an 'int'}}
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'}}
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.
342 void nonInlineFunctionCall() {
343 std::variant
<int, char> v
= 'c';
345 int a
= std::get
<int> (v
); // no-waring
346 char c
= std::get
<char> (v
); // no-warning
351 void nonInlineFunctionCallPtr() {
352 std::variant
<int, char> v
= 'c';
354 int a
= std::get
<int> (v
); // no-warning
355 char c
= std::get
<char> (v
); // no-warning