llvm/clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

// 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<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);
}