r220087 - Add support for initializer lists on field initializers for -Wuninitialized
Richard Trieu
rtrieu at google.com
Fri Oct 17 13:56:10 PDT 2014
Author: rtrieu
Date: Fri Oct 17 15:56:10 2014
New Revision: 220087
URL: http://llvm.org/viewvc/llvm-project?rev=220087&view=rev
Log:
Add support for initializer lists on field initializers for -Wuninitialized
Modified:
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/SemaCXX/uninitialized.cpp
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=220087&r1=220086&r2=220087&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Oct 17 15:56:10 2014
@@ -2216,13 +2216,61 @@ namespace {
// nodes. These Decls may have been initialized in the prior initializer.
llvm::SmallVector<ValueDecl*, 4> 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<unsigned, 4> InitFieldIndex;
+
public:
typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
UninitializedFieldVisitor(Sema &S,
llvm::SmallPtrSetImpl<ValueDecl*> &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<FieldDecl*, 4> Fields;
+ bool ReferenceField = false;
+ while (ME) {
+ FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!FD)
+ return false;
+ Fields.push_back(FD);
+ if (FD->getType()->isReferenceType())
+ ReferenceField = true;
+ ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParenImpCasts());
+ }
+
+ // Binding a reference to an unintialized field is not an
+ // uninitialized use.
+ if (CheckReferenceOnly && !ReferenceField)
+ return true;
+
+ llvm::SmallVector<unsigned, 4> 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<EnumConstantDecl>(ME->getMemberDecl()))
@@ -2235,20 +2283,19 @@ namespace {
bool AllPODFields = FieldME->getType().isPODType(S.Context);
Expr *Base = ME;
- while (isa<MemberExpr>(Base)) {
- ME = cast<MemberExpr>(Base);
+ while (MemberExpr *SubME = dyn_cast<MemberExpr>(Base)) {
- if (isa<VarDecl>(ME->getMemberDecl()))
+ if (isa<VarDecl>(SubME->getMemberDecl()))
return;
- if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(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<CXXThisExpr>(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<InitListExpr>(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<InitListExpr>(E);
+
+ if (ILE && Field) {
+ InitList = true;
+ InitListFieldDecl = Field;
+ InitFieldIndex.clear();
+ CheckInitListExpr(ILE);
+ } else {
+ InitList = false;
+ Visit(E);
+ }
+
if (Field)
Decls.erase(Field);
}
Modified: cfe/trunk/test/SemaCXX/uninitialized.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/uninitialized.cpp?rev=220087&r1=220086&r2=220087&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/uninitialized.cpp (original)
+++ cfe/trunk/test/SemaCXX/uninitialized.cpp Fri Oct 17 15:56:10 2014
@@ -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}}
+ {}
+ };
+}
More information about the cfe-commits
mailing list