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