386 lines · cpp
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.StdVariant5 6#include "Inputs/system-header-simulator-cxx.h"7 8class Foo{};9 10void clang_analyzer_warnIfReached();11void clang_analyzer_eval(int);12 13//helper functions14void changeVariantType(std::variant<int, char> &v) {15 v = 25;16}17 18void changesToInt(std::variant<int, char> &v);19void changesToInt(std::variant<int, char> *v);20 21void cannotChangePtr(const std::variant<int, char> &v);22void cannotChangePtr(const std::variant<int, char> *v);23 24char getUnknownChar();25 26void 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 32void 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 39void changeVariantPtr(std::variant<int, char> *v) {40 *v = 'c';41}42 43using var_t = std::variant<int, char>;44using var_tt = var_t;45using int_t = int;46using char_t = char;47 48// A quick sanity check to see that std::variant's std::get49// is not being confused with std::pairs std::get.50void 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::get60//----------------------------------------------------------------------------//61void 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 69void 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 79void 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 86void 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 95void 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 assignments103//----------------------------------------------------------------------------//104void 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 113void 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 123void 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 134void 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 151void 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 correctly160void 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 168void 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 correctly177void 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 187std::variant<int, char> get_unknown_variant();188// Verify that the copy constructor is handles properly when the std::variant189// has no previously activated type and we copy an object of unknown value in it.190void 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-waring194 char c = std::get<char>(v); // no-warning195 (void)a;196 (void)c;197}198 199// Verify that the copy constructor is handles properly when the std::variant200// has previously activated type and we copy an object of unknown value in it.201void 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-waring206 char c = std::get<char>(v); // no-warning207 (void)a;208 (void)c;209}210 211//----------------------------------------------------------------------------//212// typedef213//----------------------------------------------------------------------------//214 215void 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 223void 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 231void 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 239void 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 247void 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 256void 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 265void 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 functions276//----------------------------------------------------------------------------//277 278// Verifying that we are not invalidating the memory region of a variant if279// a non inlined or inlined function takes it as a constant reference or pointer280void 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 289void 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 298void 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 when309// it is passed to an inlined function as a reference or pointer310void 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 319void 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 331void 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 is341// passed as a non const reference or a pointer to a non inlined function.342void nonInlineFunctionCall() {343 std::variant<int, char> v = 'c';344 changesToInt(v);345 int a = std::get<int> (v); // no-waring346 char c = std::get<char> (v); // no-warning347 (void)a;348 (void)c;349}350 351void nonInlineFunctionCallPtr() {352 std::variant<int, char> v = 'c';353 changesToInt(&v);354 int a = std::get<int> (v); // no-warning355 char c = std::get<char> (v); // no-warning356 (void)a;357 (void)c;358}359 360// ----------------------------------------------------------------------------//361// Misc362// ----------------------------------------------------------------------------//363 364void unknownVal() {365 // force the argument to be UnknownVal366 (void)std::get<int>(*(std::variant<int, float>*)(int)3.14f); // no crash367}368 369template <typename T>370using MyVariant = std::variant<int, float>;371 372void typeAlias() {373 MyVariant<bool> v;374 375 (void)std::get<int>(v); // no-warning376}377 378template <template<typename> typename Container>379using MySpecialVariant = std::variant<int, float>;380 381void complexTypeAlias() {382 MySpecialVariant<std::vector> v;383 384 (void)std::get<int>(v); // no crash385}386