| // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,optin.cplusplus.UninitializedObject \ | |
| // RUN: -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \ | |
| // RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \ | |
| // RUN: -std=c++11 -verify %s | |
| // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,optin.cplusplus.UninitializedObject \ | |
| // RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \ | |
| // RUN: -std=c++11 -verify %s | |
| //===----------------------------------------------------------------------===// | |
| // Concrete location tests. | |
| //===----------------------------------------------------------------------===// | |
| struct ConcreteIntLocTest { | |
| int *ptr; | |
| ConcreteIntLocTest() : ptr(reinterpret_cast<int *>(0xDEADBEEF)) {} | |
| }; | |
| void fConcreteIntLocTest() { | |
| ConcreteIntLocTest(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // nonloc::LocAsInteger tests. | |
| //===----------------------------------------------------------------------===// | |
| using intptr_t = unsigned long long; | |
| struct LocAsIntegerTest { | |
| intptr_t ptr; // expected-note{{uninitialized pointee 'reinterpret_cast<char *>(this->ptr)'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| LocAsIntegerTest(void *ptr) : ptr(reinterpret_cast<intptr_t>(ptr)) {} // expected-warning{{1 uninitialized field}} | |
| }; | |
| void fLocAsIntegerTest() { | |
| char c; | |
| LocAsIntegerTest t(&c); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Null pointer tests. | |
| //===----------------------------------------------------------------------===// | |
| class NullPtrTest { | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| float *fptr = nullptr; | |
| int *ptr; | |
| RecordType *recPtr; | |
| public: | |
| NullPtrTest() : ptr(nullptr), recPtr(nullptr) { | |
| // All good! | |
| } | |
| }; | |
| void fNullPtrTest() { | |
| NullPtrTest(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Alloca tests. | |
| //===----------------------------------------------------------------------===// | |
| struct UntypedAllocaTest { | |
| void *allocaPtr; | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| // expected-warning-re@+3 {{Address of stack memory allocated by call to \ | |
| alloca() on line {{[0-9]+}} is still referred to by a temporary object on the \ | |
| stack upon returning to the caller. This will be a dangling reference}} | |
| UntypedAllocaTest() : allocaPtr(__builtin_alloca(sizeof(int))) { | |
| // All good! | |
| } | |
| }; | |
| void fUntypedAllocaTest() { | |
| UntypedAllocaTest(); | |
| } | |
| struct TypedAllocaTest1 { | |
| int *allocaPtr; // expected-note{{uninitialized pointee 'this->allocaPtr'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| TypedAllocaTest1() // expected-warning{{1 uninitialized field}} | |
| : allocaPtr(static_cast<int *>(__builtin_alloca(sizeof(int)))) {} | |
| // expected-warning-re@-2 {{Address of stack memory allocated by call to \ | |
| alloca() on line {{[0-9]+}} is still referred to by a temporary object on the \ | |
| stack upon returning to the caller. This will be a dangling reference}} | |
| }; | |
| void fTypedAllocaTest1() { | |
| TypedAllocaTest1(); | |
| } | |
| struct TypedAllocaTest2 { | |
| int *allocaPtr; | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| // expected-warning-re@+5 {{Address of stack memory allocated by call to \ | |
| alloca() on line {{[0-9]+}} is still referred to by a temporary object on the \ | |
| stack upon returning to the caller. This will be a dangling reference}} | |
| TypedAllocaTest2() | |
| : allocaPtr(static_cast<int *>(__builtin_alloca(sizeof(int)))) { | |
| *allocaPtr = 55555; | |
| // All good! | |
| } | |
| }; | |
| void fTypedAllocaTest2() { | |
| TypedAllocaTest2(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Heap pointer tests. | |
| //===----------------------------------------------------------------------===// | |
| class HeapPointerTest1 { | |
| struct RecordType { | |
| // TODO: we'd expect the note: {{uninitialized field 'this->recPtr->y'}} | |
| int x; // no-note | |
| // TODO: we'd expect the note: {{uninitialized field 'this->recPtr->y'}} | |
| int y; // no-note | |
| }; | |
| // TODO: we'd expect the note: {{uninitialized pointee 'this->fptr'}} | |
| float *fptr = new float; // no-note | |
| // TODO: we'd expect the note: {{uninitialized pointee 'this->ptr'}} | |
| int *ptr; // no-note | |
| RecordType *recPtr; | |
| public: | |
| // TODO: we'd expect the warning: {{4 uninitialized fields}} | |
| HeapPointerTest1() : ptr(new int), recPtr(new RecordType) { // no-note | |
| } | |
| }; | |
| void fHeapPointerTest1() { | |
| HeapPointerTest1(); | |
| } | |
| class HeapPointerTest2 { | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| float *fptr = new float(); // initializes to 0 | |
| int *ptr; | |
| RecordType *recPtr; | |
| public: | |
| HeapPointerTest2() : ptr(new int{25}), recPtr(new RecordType{26, 27}) { | |
| // All good! | |
| } | |
| }; | |
| void fHeapPointerTest2() { | |
| HeapPointerTest2(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Stack pointer tests. | |
| //===----------------------------------------------------------------------===// | |
| class StackPointerTest1 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| int *ptr; | |
| RecordType *recPtr; | |
| public: | |
| StackPointerTest1(int *_ptr, StackPointerTest1::RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) { | |
| // All good! | |
| } | |
| }; | |
| void fStackPointerTest1() { | |
| int ok_a = 28; | |
| StackPointerTest1::RecordType ok_rec{29, 30}; | |
| StackPointerTest1(&ok_a, &ok_rec); // 'a', 'rec.x', 'rec.y' uninitialized | |
| } | |
| #ifdef PEDANTIC | |
| class StackPointerTest2 { | |
| public: | |
| struct RecordType { | |
| int x; // expected-note{{uninitialized field 'this->recPtr->x'}} | |
| int y; // expected-note{{uninitialized field 'this->recPtr->y'}} | |
| }; | |
| private: | |
| int *ptr; // expected-note{{uninitialized pointee 'this->ptr'}} | |
| RecordType *recPtr; | |
| public: | |
| StackPointerTest2(int *_ptr, RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) { // expected-warning{{3 uninitialized fields}} | |
| } | |
| }; | |
| void fStackPointerTest2() { | |
| int a; | |
| StackPointerTest2::RecordType rec; | |
| StackPointerTest2(&a, &rec); // 'a', 'rec.x', 'rec.y' uninitialized | |
| } | |
| #else | |
| class StackPointerTest2 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| int *ptr; | |
| RecordType *recPtr; | |
| public: | |
| StackPointerTest2(int *_ptr, RecordType *_recPtr) : ptr(_ptr), recPtr(_recPtr) { | |
| } | |
| }; | |
| void fStackPointerTest2() { | |
| int a; | |
| StackPointerTest2::RecordType rec; | |
| StackPointerTest2(&a, &rec); // 'a', 'rec.x', 'rec.y' uninitialized | |
| } | |
| #endif // PEDANTIC | |
| class UninitPointerTest { | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| int *ptr; // expected-note{{uninitialized pointer 'this->ptr'}} | |
| RecordType *recPtr; | |
| public: | |
| UninitPointerTest() : recPtr(new RecordType{13, 13}) { // expected-warning{{1 uninitialized field}} | |
| } | |
| }; | |
| void fUninitPointerTest() { | |
| UninitPointerTest(); | |
| } | |
| struct CharPointerTest { | |
| const char *str; | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| CharPointerTest() : str("") {} | |
| }; | |
| void fCharPointerTest() { | |
| CharPointerTest(); | |
| } | |
| struct VectorSizePointer { | |
| VectorSizePointer() {} // expected-warning{{1 uninitialized field}} | |
| __attribute__((__vector_size__(8))) int *x; // expected-note{{uninitialized pointer 'this->x'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| }; | |
| void __vector_size__PointerTest() { | |
| VectorSizePointer v; | |
| } | |
| struct VectorSizePointee { | |
| using MyVectorType = __attribute__((__vector_size__(8))) int; | |
| MyVectorType *x; | |
| VectorSizePointee(decltype(x) x) : x(x) {} | |
| }; | |
| void __vector_size__PointeeTest() { | |
| VectorSizePointee::MyVectorType i; | |
| // TODO: Report v.x's pointee. | |
| VectorSizePointee v(&i); | |
| } | |
| struct CyclicPointerTest1 { | |
| int *ptr; // expected-note{{object references itself 'this->ptr'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| CyclicPointerTest1() : ptr(reinterpret_cast<int *>(&ptr)) {} // expected-warning{{1 uninitialized field}} | |
| }; | |
| void fCyclicPointerTest1() { | |
| CyclicPointerTest1(); | |
| } | |
| struct CyclicPointerTest2 { | |
| int **pptr; // expected-note{{object references itself 'this->pptr'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| CyclicPointerTest2() : pptr(reinterpret_cast<int **>(&pptr)) {} // expected-warning{{1 uninitialized field}} | |
| }; | |
| void fCyclicPointerTest2() { | |
| CyclicPointerTest2(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Void pointer tests. | |
| //===----------------------------------------------------------------------===// | |
| // Void pointer tests are mainly no-crash tests. | |
| typedef __typeof(sizeof(int)) size_t; | |
| void *calloc(size_t nmemb, size_t size); | |
| void free(void *p); | |
| class VoidPointerTest1 { | |
| void *vptr; | |
| public: | |
| VoidPointerTest1(void *vptr, char) : vptr(vptr) { | |
| // All good! | |
| } | |
| }; | |
| void fVoidPointerTest1() { | |
| void *vptr = calloc(1, sizeof(int)); | |
| VoidPointerTest1(vptr, char()); | |
| free(vptr); | |
| } | |
| class VoidPointerTest2 { | |
| void **vpptr; | |
| public: | |
| VoidPointerTest2(void **vpptr, char) : vpptr(vpptr) { | |
| // All good! | |
| } | |
| }; | |
| void fVoidPointerTest2() { | |
| void *vptr = calloc(1, sizeof(int)); | |
| VoidPointerTest2(&vptr, char()); | |
| free(vptr); | |
| } | |
| class VoidPointerRRefTest1 { | |
| void *&&vptrrref; // expected-note {{here}} | |
| public: | |
| // expected-warning@+3 {{Address of stack memory associated with local \ | |
| variable 'vptr' is still referred to by a temporary object on the stack \ | |
| upon returning to the caller. This will be a dangling reference}} | |
| VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void *&&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to stack allocated parameter 'vptr'}} | |
| // All good! | |
| } | |
| }; | |
| void fVoidPointerRRefTest1() { | |
| void *vptr = calloc(1, sizeof(int)); | |
| VoidPointerRRefTest1(vptr, char()); | |
| free(vptr); | |
| } | |
| class VoidPointerRRefTest2 { | |
| void **&&vpptrrref; // expected-note {{here}} | |
| public: | |
| // expected-warning@+3 {{Address of stack memory associated with local \ | |
| variable 'vptr' is still referred to by a temporary object on the stack \ | |
| upon returning to the caller. This will be a dangling reference}} | |
| VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void **&&>(vptr)) { // expected-warning {{binding reference member 'vpptrrref' to stack allocated parameter 'vptr'}} | |
| // All good! | |
| } | |
| }; | |
| void fVoidPointerRRefTest2() { | |
| void *vptr = calloc(1, sizeof(int)); | |
| VoidPointerRRefTest2(&vptr, char()); | |
| free(vptr); | |
| } | |
| class VoidPointerLRefTest { | |
| void *&vptrrref; // expected-note {{here}} | |
| public: | |
| // expected-warning@+3 {{Address of stack memory associated with local \ | |
| variable 'vptr' is still referred to by a temporary object on the stack \ | |
| upon returning to the caller. This will be a dangling reference}} | |
| VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void *&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to stack allocated parameter 'vptr'}} | |
| // All good! | |
| } | |
| }; | |
| void fVoidPointerLRefTest() { | |
| void *vptr = calloc(1, sizeof(int)); | |
| VoidPointerLRefTest(vptr, char()); | |
| free(vptr); | |
| } | |
| struct CyclicVoidPointerTest { | |
| void *vptr; // expected-note{{object references itself 'this->vptr'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| CyclicVoidPointerTest() : vptr(&vptr) {} // expected-warning{{1 uninitialized field}} | |
| }; | |
| void fCyclicVoidPointerTest() { | |
| CyclicVoidPointerTest(); | |
| } | |
| struct IntDynTypedVoidPointerTest1 { | |
| void *vptr; // expected-note{{uninitialized pointee 'static_cast<int *>(this->vptr)'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}} | |
| }; | |
| void fIntDynTypedVoidPointerTest1() { | |
| int a; | |
| IntDynTypedVoidPointerTest1 tmp(&a); | |
| } | |
| struct RecordDynTypedVoidPointerTest { | |
| struct RecordType { | |
| int x; // expected-note{{uninitialized field 'static_cast<RecordDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}} | |
| int y; // expected-note{{uninitialized field 'static_cast<RecordDynTypedVoidPointerTest::RecordType *>(this->vptr)->y'}} | |
| }; | |
| void *vptr; | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| RecordDynTypedVoidPointerTest(void *vptr) : vptr(vptr) {} // expected-warning{{2 uninitialized fields}} | |
| }; | |
| void fRecordDynTypedVoidPointerTest() { | |
| RecordDynTypedVoidPointerTest::RecordType a; | |
| RecordDynTypedVoidPointerTest tmp(&a); | |
| } | |
| struct NestedNonVoidDynTypedVoidPointerTest { | |
| struct RecordType { | |
| int x; // expected-note{{uninitialized field 'static_cast<NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}} | |
| int y; // expected-note{{uninitialized field 'static_cast<NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->y'}} | |
| void *vptr; // expected-note{{uninitialized pointee 'static_cast<char *>(static_cast<NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->vptr)'}} | |
| }; | |
| void *vptr; | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| NestedNonVoidDynTypedVoidPointerTest(void *vptr, void *c) : vptr(vptr) { | |
| static_cast<RecordType *>(vptr)->vptr = c; // expected-warning{{3 uninitialized fields}} | |
| } | |
| }; | |
| void fNestedNonVoidDynTypedVoidPointerTest() { | |
| NestedNonVoidDynTypedVoidPointerTest::RecordType a; | |
| char c; | |
| NestedNonVoidDynTypedVoidPointerTest tmp(&a, &c); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Multipointer tests. | |
| //===----------------------------------------------------------------------===// | |
| #ifdef PEDANTIC | |
| class MultiPointerTest1 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| RecordType **mptr; // expected-note{{uninitialized pointee 'this->mptr'}} | |
| public: | |
| MultiPointerTest1(RecordType **p, int) : mptr(p) { // expected-warning{{1 uninitialized field}} | |
| } | |
| }; | |
| void fMultiPointerTest1() { | |
| MultiPointerTest1::RecordType *p1; | |
| MultiPointerTest1::RecordType **mptr = &p1; | |
| MultiPointerTest1(mptr, int()); // '*mptr' uninitialized | |
| } | |
| #else | |
| class MultiPointerTest1 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| RecordType **mptr; | |
| public: | |
| MultiPointerTest1(RecordType **p, int) : mptr(p) {} | |
| }; | |
| void fMultiPointerTest1() { | |
| MultiPointerTest1::RecordType *p1; | |
| MultiPointerTest1::RecordType **mptr = &p1; | |
| MultiPointerTest1(mptr, int()); // '*mptr' uninitialized | |
| } | |
| #endif // PEDANTIC | |
| #ifdef PEDANTIC | |
| class MultiPointerTest2 { | |
| public: | |
| struct RecordType { | |
| int x; // expected-note{{uninitialized field 'this->mptr->x'}} | |
| int y; // expected-note{{uninitialized field 'this->mptr->y'}} | |
| }; | |
| private: | |
| RecordType **mptr; | |
| public: | |
| MultiPointerTest2(RecordType **p, int) : mptr(p) { // expected-warning{{2 uninitialized fields}} | |
| } | |
| }; | |
| void fMultiPointerTest2() { | |
| MultiPointerTest2::RecordType i; | |
| MultiPointerTest2::RecordType *p1 = &i; | |
| MultiPointerTest2::RecordType **mptr = &p1; | |
| MultiPointerTest2(mptr, int()); // '**mptr' uninitialized | |
| } | |
| #else | |
| class MultiPointerTest2 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| RecordType **mptr; | |
| public: | |
| MultiPointerTest2(RecordType **p, int) : mptr(p) { | |
| } | |
| }; | |
| void fMultiPointerTest2() { | |
| MultiPointerTest2::RecordType i; | |
| MultiPointerTest2::RecordType *p1 = &i; | |
| MultiPointerTest2::RecordType **mptr = &p1; | |
| MultiPointerTest2(mptr, int()); // '**mptr' uninitialized | |
| } | |
| #endif // PEDANTIC | |
| class MultiPointerTest3 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| RecordType **mptr; | |
| public: | |
| MultiPointerTest3(RecordType **p, int) : mptr(p) { | |
| // All good! | |
| } | |
| }; | |
| void fMultiPointerTest3() { | |
| MultiPointerTest3::RecordType i{31, 32}; | |
| MultiPointerTest3::RecordType *p1 = &i; | |
| MultiPointerTest3::RecordType **mptr = &p1; | |
| MultiPointerTest3(mptr, int()); // '**mptr' uninitialized | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Incomplete pointee tests. | |
| //===----------------------------------------------------------------------===// | |
| class IncompleteType; | |
| struct IncompletePointeeTypeTest { | |
| IncompleteType *pImpl; //no-crash | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| IncompletePointeeTypeTest(IncompleteType *A) : pImpl(A) {} | |
| }; | |
| void fIncompletePointeeTypeTest(void *ptr) { | |
| IncompletePointeeTypeTest(reinterpret_cast<IncompleteType *>(ptr)); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Function pointer tests. | |
| //===----------------------------------------------------------------------===// | |
| struct FunctionPointerWithDifferentDynTypeTest { | |
| using Func1 = void *(*)(); | |
| using Func2 = int *(*)(); | |
| Func1 f; // no-crash | |
| FunctionPointerWithDifferentDynTypeTest(Func2 f) : f((Func1)f) {} | |
| }; | |
| // Note that there isn't a function calling the constructor of | |
| // FunctionPointerWithDifferentDynTypeTest, because a crash could only be | |
| // reproduced without it. | |
| //===----------------------------------------------------------------------===// | |
| // Member pointer tests. | |
| //===----------------------------------------------------------------------===// | |
| struct UsefulFunctions { | |
| int a, b; | |
| void print() {} | |
| void dump() {} | |
| }; | |
| #ifdef PEDANTIC | |
| struct PointerToMemberFunctionTest1 { | |
| void (UsefulFunctions::*f)(void); // expected-note{{uninitialized field 'this->f'}} | |
| PointerToMemberFunctionTest1() {} | |
| }; | |
| void fPointerToMemberFunctionTest1() { | |
| PointerToMemberFunctionTest1(); // expected-warning{{1 uninitialized field}} | |
| } | |
| struct PointerToMemberFunctionTest2 { | |
| void (UsefulFunctions::*f)(void); | |
| PointerToMemberFunctionTest2(void (UsefulFunctions::*f)(void)) : f(f) { | |
| // All good! | |
| } | |
| }; | |
| void fPointerToMemberFunctionTest2() { | |
| void (UsefulFunctions::*f)(void) = &UsefulFunctions::print; | |
| PointerToMemberFunctionTest2 a(f); | |
| } | |
| struct MultiPointerToMemberFunctionTest1 { | |
| void (UsefulFunctions::**f)(void); // expected-note{{uninitialized pointer 'this->f'}} | |
| MultiPointerToMemberFunctionTest1() {} | |
| }; | |
| void fMultiPointerToMemberFunctionTest1() { | |
| MultiPointerToMemberFunctionTest1(); // expected-warning{{1 uninitialized field}} | |
| } | |
| struct MultiPointerToMemberFunctionTest2 { | |
| void (UsefulFunctions::**f)(void); | |
| MultiPointerToMemberFunctionTest2(void (UsefulFunctions::**f)(void)) : f(f) { | |
| // All good! | |
| } | |
| }; | |
| void fMultiPointerToMemberFunctionTest2() { | |
| void (UsefulFunctions::*f)(void) = &UsefulFunctions::print; | |
| MultiPointerToMemberFunctionTest2 a(&f); | |
| } | |
| struct PointerToMemberDataTest1 { | |
| int UsefulFunctions::*d; // expected-note{{uninitialized field 'this->d'}} | |
| PointerToMemberDataTest1() {} | |
| }; | |
| void fPointerToMemberDataTest1() { | |
| PointerToMemberDataTest1(); // expected-warning{{1 uninitialized field}} | |
| } | |
| struct PointerToMemberDataTest2 { | |
| int UsefulFunctions::*d; | |
| PointerToMemberDataTest2(int UsefulFunctions::*d) : d(d) { | |
| // All good! | |
| } | |
| }; | |
| void fPointerToMemberDataTest2() { | |
| int UsefulFunctions::*d = &UsefulFunctions::a; | |
| PointerToMemberDataTest2 a(d); | |
| } | |
| struct MultiPointerToMemberDataTest1 { | |
| int UsefulFunctions::**d; // expected-note{{uninitialized pointer 'this->d'}} | |
| MultiPointerToMemberDataTest1() {} | |
| }; | |
| void fMultiPointerToMemberDataTest1() { | |
| MultiPointerToMemberDataTest1(); // expected-warning{{1 uninitialized field}} | |
| } | |
| struct MultiPointerToMemberDataTest2 { | |
| int UsefulFunctions::**d; | |
| MultiPointerToMemberDataTest2(int UsefulFunctions::**d) : d(d) { | |
| // All good! | |
| } | |
| }; | |
| void fMultiPointerToMemberDataTest2() { | |
| int UsefulFunctions::*d = &UsefulFunctions::a; | |
| MultiPointerToMemberDataTest2 a(&d); | |
| } | |
| #endif // PEDANTIC | |
| //===----------------------------------------------------------------------===// | |
| // Tests for list-like records. | |
| //===----------------------------------------------------------------------===// | |
| class ListTest1 { | |
| public: | |
| struct Node { | |
| Node *next = nullptr; // no crash | |
| int i; | |
| }; | |
| private: | |
| Node *head = nullptr; | |
| public: | |
| ListTest1() { | |
| // All good! | |
| } | |
| }; | |
| void fListTest1() { | |
| ListTest1(); | |
| } | |
| class ListTest2 { | |
| public: | |
| struct Node { | |
| Node *next = nullptr; | |
| int i; // expected-note{{uninitialized field 'this->head->i'}} | |
| }; | |
| private: | |
| Node *head = nullptr; | |
| public: | |
| ListTest2(Node *node, int) : head(node) { // expected-warning{{1 uninitialized field}} | |
| } | |
| }; | |
| void fListTest2() { | |
| ListTest2::Node n; | |
| ListTest2(&n, int()); | |
| } | |
| class CyclicList { | |
| public: | |
| struct Node { | |
| Node *next = nullptr; | |
| int i; // expected-note{{uninitialized field 'this->head->i'}} | |
| }; | |
| private: | |
| Node *head = nullptr; | |
| public: | |
| CyclicList(Node *node, int) : head(node) { // expected-warning{{1 uninitialized field}} | |
| } | |
| }; | |
| void fCyclicList() { | |
| /* | |
| n3 | |
| / \ | |
| this -- n1 -- n2 | |
| */ | |
| CyclicList::Node n1; | |
| CyclicList::Node n2; | |
| n2.next = &n1; | |
| n2.i = 50; | |
| CyclicList::Node n3; | |
| n3.next = &n2; | |
| n3.i = 50; | |
| n1.next = &n3; | |
| // note that n1.i is uninitialized | |
| CyclicList(&n1, int()); | |
| } | |
| struct RingListTest { | |
| RingListTest *next; // no-crash | |
| RingListTest() : next(this) {} | |
| }; | |
| void fRingListTest() { | |
| RingListTest(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Tests for classes containing references. | |
| //===----------------------------------------------------------------------===// | |
| class ReferenceTest1 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| RecordType &lref; | |
| RecordType &&rref; | |
| public: | |
| ReferenceTest1(RecordType &lref, RecordType &rref) : lref(lref), rref(static_cast<RecordType &&>(rref)) { | |
| // All good! | |
| } | |
| }; | |
| void fReferenceTest1() { | |
| ReferenceTest1::RecordType d{33, 34}; | |
| ReferenceTest1(d, d); | |
| } | |
| #ifdef PEDANTIC | |
| class ReferenceTest2 { | |
| public: | |
| struct RecordType { | |
| int x; // expected-note{{uninitialized field 'this->lref.x'}} | |
| int y; // expected-note{{uninitialized field 'this->lref.y'}} | |
| }; | |
| private: | |
| RecordType &lref; | |
| RecordType &&rref; | |
| public: | |
| ReferenceTest2(RecordType &lref, RecordType &rref) | |
| : lref(lref), rref(static_cast<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}} | |
| } | |
| }; | |
| void fReferenceTest2() { | |
| ReferenceTest2::RecordType c; | |
| ReferenceTest2(c, c); | |
| } | |
| #else | |
| class ReferenceTest2 { | |
| public: | |
| struct RecordType { | |
| int x; | |
| int y; | |
| }; | |
| private: | |
| RecordType &lref; | |
| RecordType &&rref; | |
| public: | |
| ReferenceTest2(RecordType &lref, RecordType &rref) | |
| : lref(lref), rref(static_cast<RecordType &&>(rref)) { | |
| } | |
| }; | |
| void fReferenceTest2() { | |
| ReferenceTest2::RecordType c; | |
| ReferenceTest2(c, c); | |
| } | |
| #endif // PEDANTIC | |
| class ReferenceTest3 { | |
| public: | |
| struct RecordType { | |
| int x; // expected-note{{uninitialized field 'this->lref.x'}} | |
| int y; // expected-note{{uninitialized field 'this->lref.y'}} | |
| }; | |
| private: | |
| RecordType &lref; | |
| RecordType &&rref; | |
| public: | |
| ReferenceTest3(RecordType &lref, RecordType &rref) | |
| : lref(lref), rref(static_cast<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}} | |
| } | |
| }; | |
| void fReferenceTest3() { | |
| ReferenceTest3::RecordType c, d{35, 36}; | |
| ReferenceTest3(c, d); | |
| } | |
| class ReferenceTest4 { | |
| public: | |
| struct RecordType { | |
| int x; // expected-note{{uninitialized field 'this->rref.x'}} | |
| int y; // expected-note{{uninitialized field 'this->rref.y'}} | |
| }; | |
| private: | |
| RecordType &lref; | |
| RecordType &&rref; | |
| public: | |
| ReferenceTest4(RecordType &lref, RecordType &rref) | |
| : lref(lref), rref(static_cast<RecordType &&>(rref)) { // expected-warning{{2 uninitialized fields}} | |
| } | |
| }; | |
| void fReferenceTest5() { | |
| ReferenceTest4::RecordType c, d{37, 38}; | |
| ReferenceTest4(d, c); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Tests for objects containing multiple references to the same object. | |
| //===----------------------------------------------------------------------===// | |
| struct IntMultipleReferenceToSameObjectTest { | |
| int *iptr; // expected-note{{uninitialized pointee 'this->iptr'}} | |
| int &iref; // no-note, pointee of this->iref was already reported | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| IntMultipleReferenceToSameObjectTest(int *i) : iptr(i), iref(*i) {} // expected-warning{{1 uninitialized field}} | |
| }; | |
| void fIntMultipleReferenceToSameObjectTest() { | |
| int a; | |
| IntMultipleReferenceToSameObjectTest Test(&a); | |
| } | |
| struct IntReferenceWrapper1 { | |
| int &a; // expected-note{{uninitialized pointee 'this->a'}} | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| IntReferenceWrapper1(int &a) : a(a) {} // expected-warning{{1 uninitialized field}} | |
| }; | |
| struct IntReferenceWrapper2 { | |
| int &a; // no-note, pointee of this->a was already reported | |
| int dontGetFilteredByNonPedanticMode = 0; | |
| IntReferenceWrapper2(int &a) : a(a) {} // no-warning | |
| }; | |
| void fMultipleObjectsReferencingTheSameObjectTest() { | |
| int a; | |
| IntReferenceWrapper1 T1(a); | |
| IntReferenceWrapper2 T2(a); | |
| } |