llvm-project/clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
Matheus Izvekov 14f7bd63b9
Reland: [clang] preserve class type sugar when taking pointer to member (#132401)
Original PR: #130537
Originally reverted due to revert of dependent commit. Relanding with no
changes.

This changes the MemberPointerType representation to use a
NestedNameSpecifier instead of a Type to represent the base class.

Since the qualifiers are always parsed as nested names, there was an
impedance mismatch when converting these back and forth into types, and
this led to issues in preserving sugar.

The nested names are indeed a better match for these, as the differences
which a QualType can represent cannot be expressed syntatically, and
they represent the use case more exactly, being either dependent or
referring to a CXXRecord, unqualified.

This patch also makes the MemberPointerType able to represent sugar for
a {up/downcast}cast conversion of the base class, although for now the
underlying type is canonical, as preserving the sugar up to that point
requires further work.

As usual, includes a few drive-by fixes in order to make use of the
improvements.
2025-03-21 13:20:52 -03:00

958 lines
24 KiB
C++

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