r231068 - Make -Wuninitialized warn on pointer-to-member and comma operators.

Manuel Klimek klimek at google.com
Tue Mar 3 06:54:26 PST 2015


Author: klimek
Date: Tue Mar  3 08:54:25 2015
New Revision: 231068

URL: http://llvm.org/viewvc/llvm-project?rev=231068&view=rev
Log:
Make -Wuninitialized warn on pointer-to-member and comma operators.

`isTrackedVar` has been updated to also track records.
`DeclRefExpr`s appearing on the left side of a comma operator are
ignored, while those appearing on the right side are classified as
`Use`.

Patch by Enrico Pertoso.

Modified:
    cfe/trunk/lib/Analysis/UninitializedValues.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/SemaCXX/uninitialized.cpp

Modified: cfe/trunk/lib/Analysis/UninitializedValues.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/UninitializedValues.cpp?rev=231068&r1=231067&r2=231068&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/UninitializedValues.cpp (original)
+++ cfe/trunk/lib/Analysis/UninitializedValues.cpp Tue Mar  3 08:54:25 2015
@@ -14,6 +14,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Analysis/Analyses/PostOrderCFGView.h"
 #include "clang/Analysis/Analyses/UninitializedValues.h"
@@ -37,7 +38,7 @@ static bool isTrackedVar(const VarDecl *
       !vd->isExceptionVariable() && !vd->isInitCapture() &&
       vd->getDeclContext() == dc) {
     QualType ty = vd->getType();
-    return ty->isScalarType() || ty->isVectorType();
+    return ty->isScalarType() || ty->isVectorType() || ty->isRecordType();
   }
   return false;
 }
@@ -347,6 +348,7 @@ public:
 }
 
 static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
+  if (VD->getType()->isRecordType()) return nullptr;
   if (Expr *Init = VD->getInit()) {
     const DeclRefExpr *DRE
       = dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init));
@@ -376,10 +378,26 @@ void ClassifyRefs::classify(const Expr *
     return;
   }
 
+  if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+    if (VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
+      if (!VD->isStaticDataMember())
+        classify(ME->getBase(), C);
+    }
+    return;
+  }
+
   if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
-    if (BO->getOpcode() == BO_Comma)
+    switch (BO->getOpcode()) {
+    case BO_PtrMemD:
+    case BO_PtrMemI:
+      classify(BO->getLHS(), C);
+      return;
+    case BO_Comma:
       classify(BO->getRHS(), C);
-    return;
+      return;
+    default:
+      return;
+    }
   }
 
   FindVarResult Var = findVar(E, DC);
@@ -404,7 +422,7 @@ void ClassifyRefs::VisitBinaryOperator(B
   // use.
   if (BO->isCompoundAssignmentOp())
     classify(BO->getLHS(), Use);
-  else if (BO->getOpcode() == BO_Assign)
+  else if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma)
     classify(BO->getLHS(), Ignore);
 }
 
@@ -415,25 +433,40 @@ void ClassifyRefs::VisitUnaryOperator(Un
     classify(UO->getSubExpr(), Use);
 }
 
+static bool isPointerToConst(const QualType &QT) {
+  return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified();
+}
+
 void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
   // Classify arguments to std::move as used.
   if (CE->getNumArgs() == 1) {
     if (FunctionDecl *FD = CE->getDirectCallee()) {
       if (FD->isInStdNamespace() && FD->getIdentifier() &&
           FD->getIdentifier()->isStr("move")) {
-        classify(CE->getArg(0), Use);
+        // RecordTypes are handled in SemaDeclCXX.cpp.
+        if (!CE->getArg(0)->getType()->isRecordType())
+          classify(CE->getArg(0), Use);
         return;
       }
     }
   }
 
-  // If a value is passed by const reference to a function, we should not assume
-  // that it is initialized by the call, and we conservatively do not assume
-  // that it is used.
+  // If a value is passed by const pointer or by const reference to a function,
+  // we should not assume that it is initialized by the call, and we
+  // conservatively do not assume that it is used.
   for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
-       I != E; ++I)
-    if ((*I)->getType().isConstQualified() && (*I)->isGLValue())
-      classify(*I, Ignore);
+       I != E; ++I) {
+    if ((*I)->isGLValue()) {
+      if ((*I)->getType().isConstQualified())
+        classify((*I), Ignore);
+    } else if (isPointerToConst((*I)->getType())) {
+      const Expr *Ex = stripCasts(DC->getParentASTContext(), *I);
+      const UnaryOperator *UO = dyn_cast<UnaryOperator>(Ex);
+      if (UO && UO->getOpcode() == UO_AddrOf)
+        Ex = UO->getSubExpr();
+      classify(Ex, Ignore);
+    }
+  }
 }
 
 void ClassifyRefs::VisitCastExpr(CastExpr *CE) {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=231068&r1=231067&r2=231068&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Mar  3 08:54:25 2015
@@ -8582,8 +8582,13 @@ namespace {
         diag = diag::warn_uninit_self_reference_in_reference_init;
       } else if (cast<VarDecl>(OrigDecl)->isStaticLocal()) {
         diag = diag::warn_static_self_reference_in_init;
-      } else {
+      } else if (isa<TranslationUnitDecl>(OrigDecl->getDeclContext()) ||
+                 isa<NamespaceDecl>(OrigDecl->getDeclContext()) ||
+                 DRE->getDecl()->getType()->isRecordType()) {
         diag = diag::warn_uninit_self_reference_in_init;
+      } else {
+        // Local variables will be handled by the CFG analysis.
+        return;
       }
 
       S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,

Modified: cfe/trunk/test/SemaCXX/uninitialized.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/uninitialized.cpp?rev=231068&r1=231067&r2=231068&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/uninitialized.cpp (original)
+++ cfe/trunk/test/SemaCXX/uninitialized.cpp Tue Mar  3 08:54:25 2015
@@ -86,7 +86,6 @@ void test_stuff () {
   int aa = (ref(aa) += 10); // expected-warning {{variable 'aa' is uninitialized when used within its own initialization}}
   int bb = bb ? x : y; // expected-warning {{variable 'bb' is uninitialized when used within its own initialization}}
 
-
   for (;;) {
     int a = a; // no-warning: used to signal intended lack of initialization.
     int b = b + 1; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}}
@@ -124,6 +123,50 @@ void test_stuff () {
   }
 }
 
+void test_comma() {
+  int a;  // expected-note {{initialize the variable 'a' to silence this warning}}
+  int b = (a, a ?: 2);  // expected-warning {{variable 'a' is uninitialized when used here}}
+  int c = (a, a, b, c);  // expected-warning {{variable 'c' is uninitialized when used within its own initialization}}
+  int d;  // expected-note {{initialize the variable 'd' to silence this warning}}
+  int e = (foo(d), e, b); // expected-warning {{variable 'd' is uninitialized when used here}}
+  int f;  // expected-note {{initialize the variable 'f' to silence this warning}}
+  f = f + 1, 2;  // expected-warning {{variable 'f' is uninitialized when used here}}
+  int h;
+  int g = (h, g, 2);  // no-warning: h, g are evaluated but not used.
+}
+
+namespace member_ptr {
+struct A {
+  int x;
+  int y;
+  A(int x) : x{x} {}
+};
+
+void test_member_ptr() {
+  int A::* px = &A::x;
+  A a{a.*px}; // expected-warning {{variable 'a' is uninitialized when used within its own initialization}}
+  A b = b; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}}
+}
+}
+
+namespace const_ptr {
+void foo(int *a);
+void bar(const int *a);
+void foobar(const int **a);
+
+void test_const_ptr() {
+  int a;
+  int b;  // expected-note {{initialize the variable 'b' to silence this warning}}
+  foo(&a);
+  bar(&b);
+  b = a + b; // expected-warning {{variable 'b' is uninitialized when used here}}
+  int *ptr;  //expected-note {{initialize the variable 'ptr' to silence this warning}}
+  const int *ptr2;
+  foo(ptr); // expected-warning {{variable 'ptr' is uninitialized when used here}}
+  foobar(&ptr2);
+}
+}
+
 // Also test similar constructs in a field's initializer.
 struct S {
   int x;





More information about the cfe-commits mailing list