From 4f1e33719a478e813b25dcc41082b51935070d1d Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Fri, 17 Oct 2014 20:56:10 +0000 Subject: [PATCH] Add support for initializer lists on field initializers for -Wuninitialized git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220087 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclCXX.cpp | 102 ++++++++++++++++++++++++++---- test/SemaCXX/uninitialized.cpp | 110 ++++++++++++++++++++++++++++++++- 2 files changed, 199 insertions(+), 13 deletions(-) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index ed15012a16..2dbbbc3828 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2216,13 +2216,61 @@ namespace { // nodes. These Decls may have been initialized in the prior initializer. llvm::SmallVector DeclsToRemove; // If non-null, add a note to the warning pointing back to the constructor. - const CXXConstructorDecl *Constructor; + const CXXConstructorDecl *Constructor = nullptr; + // Varaibles to hold state when processing an initializer list. When + // InitList is true, special case initialization of FieldDecls matching + // InitListFieldDecl. + bool InitList = false; + FieldDecl *InitListFieldDecl = nullptr; + llvm::SmallVector InitFieldIndex; + public: typedef EvaluatedExprVisitor Inherited; UninitializedFieldVisitor(Sema &S, llvm::SmallPtrSetImpl &Decls) : Inherited(S.Context), S(S), Decls(Decls) { } + // Returns true if the use of ME is not an uninitialized use. + bool IsInitListMemberExprInitialized(MemberExpr *ME, + bool CheckReferenceOnly) { + llvm::SmallVector Fields; + bool ReferenceField = false; + while (ME) { + FieldDecl *FD = dyn_cast(ME->getMemberDecl()); + if (!FD) + return false; + Fields.push_back(FD); + if (FD->getType()->isReferenceType()) + ReferenceField = true; + ME = dyn_cast(ME->getBase()->IgnoreParenImpCasts()); + } + + // Binding a reference to an unintialized field is not an + // uninitialized use. + if (CheckReferenceOnly && !ReferenceField) + return true; + + llvm::SmallVector UsedFieldIndex; + // Discard the first field since it is the field decl that is being + // initialized. + for (auto I = Fields.rbegin() + 1, E = Fields.rend(); I != E; ++I) { + UsedFieldIndex.push_back((*I)->getFieldIndex()); + } + + for (auto UsedIter = UsedFieldIndex.begin(), + UsedEnd = UsedFieldIndex.end(), + OrigIter = InitFieldIndex.begin(), + OrigEnd = InitFieldIndex.end(); + UsedIter != UsedEnd && OrigIter != OrigEnd; ++UsedIter, ++OrigIter) { + if (*UsedIter < *OrigIter) + return true; + if (*UsedIter > *OrigIter) + break; + } + + return false; + } + void HandleMemberExpr(MemberExpr *ME, bool CheckReferenceOnly, bool AddressOf) { if (isa(ME->getMemberDecl())) @@ -2235,20 +2283,19 @@ namespace { bool AllPODFields = FieldME->getType().isPODType(S.Context); Expr *Base = ME; - while (isa(Base)) { - ME = cast(Base); + while (MemberExpr *SubME = dyn_cast(Base)) { - if (isa(ME->getMemberDecl())) + if (isa(SubME->getMemberDecl())) return; - if (FieldDecl *FD = dyn_cast(ME->getMemberDecl())) + if (FieldDecl *FD = dyn_cast(SubME->getMemberDecl())) if (!FD->isAnonymousStructOrUnion()) - FieldME = ME; + FieldME = SubME; if (!FieldME->getType().isPODType(S.Context)) AllPODFields = false; - Base = ME->getBase()->IgnoreParenImpCasts(); + Base = SubME->getBase()->IgnoreParenImpCasts(); } if (!isa(Base)) @@ -2264,9 +2311,16 @@ namespace { const bool IsReference = FoundVD->getType()->isReferenceType(); - // Prevent double warnings on use of unbounded references. - if (CheckReferenceOnly && !IsReference) - return; + if (InitList && !AddressOf && FoundVD == InitListFieldDecl) { + // Special checking for initializer lists. + if (IsInitListMemberExprInitialized(ME, CheckReferenceOnly)) { + return; + } + } else { + // Prevent double warnings on use of unbounded references. + if (CheckReferenceOnly && !IsReference) + return; + } unsigned diag = IsReference ? diag::warn_reference_field_is_uninit @@ -2326,16 +2380,40 @@ namespace { Visit(E); } + void CheckInitListExpr(InitListExpr *ILE) { + InitFieldIndex.push_back(0); + for (auto Child : ILE->children()) { + if (InitListExpr *SubList = dyn_cast(Child)) { + CheckInitListExpr(SubList); + } else { + Visit(Child); + } + ++InitFieldIndex.back(); + } + InitFieldIndex.pop_back(); + } + void CheckInitializer(Expr *E, const CXXConstructorDecl *FieldConstructor, FieldDecl *Field) { // Remove Decls that may have been initialized in the previous // initializer. for (ValueDecl* VD : DeclsToRemove) Decls.erase(VD); - DeclsToRemove.clear(); + Constructor = FieldConstructor; - Visit(E); + InitListExpr *ILE = dyn_cast(E); + + if (ILE && Field) { + InitList = true; + InitListFieldDecl = Field; + InitFieldIndex.clear(); + CheckInitListExpr(ILE); + } else { + InitList = false; + Visit(E); + } + if (Field) Decls.erase(Field); } diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp index ddf5ce6f6d..2596dd044d 100644 --- a/test/SemaCXX/uninitialized.cpp +++ b/test/SemaCXX/uninitialized.cpp @@ -1111,4 +1111,112 @@ namespace init_list { D d1 = { num, num }; D d2 = { num, d2.a }; D d3 = { d3.b, num }; // expected-warning{{uninitialized}} -}; + + // Same as above in member initializer form. + struct Awrapper { + A a1{1,2}; + A a2{a2.i1 + 2}; // expected-warning{{uninitialized}} + A a3 = {a3.i1 + 2}; // expected-warning{{uninitialized}} + A a4 = A{a4.i2 + 2}; // expected-warning{{uninitialized}} + Awrapper() {} // expected-note 3{{in this constructor}} + Awrapper(int) : + a1{1,2}, + a2{a2.i1 + 2}, // expected-warning{{uninitialized}} + a3{a3.i1 + 2}, // expected-warning{{uninitialized}} + a4{a4.i2 + 2} // expected-warning{{uninitialized}} + {} + }; + + struct Bwrapper { + B b1 = { {}, {} }; + B b2 = { {}, b2.a1 }; + B b3 = { b3.a1 }; // expected-warning{{uninitialized}} + B b4 = { {}, b4.a2} ; // expected-warning{{uninitialized}} + B b5 = { b5.a2 }; // expected-warning{{uninitialized}} + + B b6 = { {b6.a1.i1} }; // expected-warning{{uninitialized}} + B b7 = { {0, b7.a1.i1} }; + B b8 = { {}, {b8.a1.i1} }; + B b9 = { {}, {0, b9.a1.i1} }; + + B b10 = { {b10.a1.i2} }; // expected-warning{{uninitialized}} + B b11 = { {0, b11.a1.i2} }; // expected-warning{{uninitialized}} + B b12 = { {}, {b12.a1.i2} }; + B b13 = { {}, {0, b13.a1.i2} }; + + B b14 = { {b14.a2.i1} }; // expected-warning{{uninitialized}} + B b15 = { {0, b15.a2.i1} }; // expected-warning{{uninitialized}} + B b16 = { {}, {b16.a2.i1} }; // expected-warning{{uninitialized}} + B b17 = { {}, {0, b17.a2.i1} }; + + B b18 = { {b18.a2.i2} }; // expected-warning{{uninitialized}} + B b19 = { {0, b19.a2.i2} }; // expected-warning{{uninitialized}} + B b20 = { {}, {b20.a2.i2} }; // expected-warning{{uninitialized}} + B b21 = { {}, {0, b21.a2.i2} }; // expected-warning{{uninitialized}} + + B b22 = { {b18.a2.i2 + 5} }; + Bwrapper() {} // expected-note 13{{in this constructor}} + Bwrapper(int) : + b1{ {}, {} }, + b2{ {}, b2.a1 }, + b3{ b3.a1 }, // expected-warning{{uninitialized}} + b4{ {}, b4.a2}, // expected-warning{{uninitialized}} + b5{ b5.a2 }, // expected-warning{{uninitialized}} + + b6{ {b6.a1.i1} }, // expected-warning{{uninitialized}} + b7{ {0, b7.a1.i1} }, + b8{ {}, {b8.a1.i1} }, + b9{ {}, {0, b9.a1.i1} }, + + b10{ {b10.a1.i2} }, // expected-warning{{uninitialized}} + b11{ {0, b11.a1.i2} }, // expected-warning{{uninitialized}} + b12{ {}, {b12.a1.i2} }, + b13{ {}, {0, b13.a1.i2} }, + + b14{ {b14.a2.i1} }, // expected-warning{{uninitialized}} + b15{ {0, b15.a2.i1} }, // expected-warning{{uninitialized}} + b16{ {}, {b16.a2.i1} }, // expected-warning{{uninitialized}} + b17{ {}, {0, b17.a2.i1} }, + + b18{ {b18.a2.i2} }, // expected-warning{{uninitialized}} + b19{ {0, b19.a2.i2} }, // expected-warning{{uninitialized}} + b20{ {}, {b20.a2.i2} }, // expected-warning{{uninitialized}} + b21{ {}, {0, b21.a2.i2} }, // expected-warning{{uninitialized}} + + b22{ {b18.a2.i2 + 5} } + {} + }; + + struct Cwrapper { + C c1 = { 0, num, 0 }; + C c2 = { 1, num, c2.b }; + C c3 = { c3.b, num }; // expected-warning{{uninitialized}} + C c4 = { 0, c4.b, 0 }; // expected-warning{{uninitialized}} + C c5 = { 0, c5.c, 0 }; + C c6 = { c6.b, num, 0 }; // expected-warning{{uninitialized}} + C c7 = { 0, c7.a, 0 }; + + Cwrapper() {} // expected-note 3{{in this constructor}} + Cwrapper(int) : + c1{ 0, num, 0 }, + c2{ 1, num, c2.b }, + c3{ c3.b, num }, // expected-warning{{uninitialized}} + c4{ 0, c4.b, 0 }, // expected-warning{{uninitialized}} + c5{ 0, c5.c, 0 }, + c6{ c6.b, num, 0 }, // expected-warning{{uninitialized}} + c7{ 0, c7.a, 0 } + {} + }; + + struct Dwrapper { + D d1 = { num, num }; + D d2 = { num, d2.a }; + D d3 = { d3.b, num }; // expected-warning{{uninitialized}} + Dwrapper() {} // expected-note{{in this constructor}} + Dwrapper(int) : + d1{ num, num }, + d2{ num, d2.a }, + d3{ d3.b, num } // expected-warning{{uninitialized}} + {} + }; +} -- 2.40.0