Files
clang-p2996/clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
Balazs Benics 6ad47e1c4f [analyzer] Catch leaking stack addresses via stack variables
Not only global variables can hold references to dead stack variables.
Consider this example:

  void write_stack_address_to(char **q) {
    char local;
    *q = &local;
  }

  void test_stack() {
    char *p;
    write_stack_address_to(&p);
  }

The address of 'local' is assigned to 'p', which becomes a dangling
pointer after 'write_stack_address_to()' returns.

The StackAddrEscapeChecker was looking for bindings in the store which
referred to variables of the popped stack frame, but it only considered
global variables in this regard. This patch relaxes this, catching
stack variable bindings as well.

---

This patch also works for temporary objects like:

  struct Bar {
    const int &ref;
    explicit Bar(int y) : ref(y) {
      // Okay.
    } // End of the constructor call, `ref` is dangling now. Warning!
  };

  void test() {
    Bar{33}; // Temporary object, so the corresponding memregion is
             // *not* a VarRegion.
  }

---

The return value optimization aka. copy-elision might kick in but that
is modeled by passing an imaginary CXXThisRegion which refers to the
parent stack frame which is supposed to be the 'return slot'.
Objects residing in the 'return slot' outlive the scope of the inner
call, thus we should expect no warning about them - except if we
explicitly disable copy-elision.

Reviewed By: NoQ, martong

Differential Revision: https://reviews.llvm.org/D107078
2021-08-27 11:31:16 +02:00

950 lines
24 KiB
C++

// RUN: %clang_analyze_cc1 -analyzer-checker=core,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,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.
void *malloc(int size);
class VoidPointerTest1 {
void *vptr;
public:
VoidPointerTest1(void *vptr, char) : vptr(vptr) {
// All good!
}
};
void fVoidPointerTest1() {
void *vptr = malloc(sizeof(int));
VoidPointerTest1(vptr, char());
}
class VoidPointerTest2 {
void **vpptr;
public:
VoidPointerTest2(void **vpptr, char) : vpptr(vpptr) {
// All good!
}
};
void fVoidPointerTest2() {
void *vptr = malloc(sizeof(int));
VoidPointerTest2(&vptr, char());
}
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 = malloc(sizeof(int));
VoidPointerRRefTest1(vptr, char());
}
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 = malloc(sizeof(int));
VoidPointerRRefTest2(&vptr, char());
}
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 = malloc(sizeof(int));
VoidPointerLRefTest(vptr, char());
}
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<struct RecordDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}}
int y; // expected-note{{uninitialized field 'static_cast<struct 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<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->x'}}
int y; // expected-note{{uninitialized field 'static_cast<struct NestedNonVoidDynTypedVoidPointerTest::RecordType *>(this->vptr)->y'}}
void *vptr; // expected-note{{uninitialized pointee 'static_cast<char *>(static_cast<struct 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);
}