]> granicus.if.org Git - clang/commitdiff
Tweak -Wuninitialized's handling of 'int x = x' to report that as the root cause...
authorTed Kremenek <kremenek@apple.com>
Thu, 13 Oct 2011 18:50:06 +0000 (18:50 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 13 Oct 2011 18:50:06 +0000 (18:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141881 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/Analyses/UninitializedValues.h
lib/Analysis/UninitializedValues.cpp
lib/Sema/AnalysisBasedWarnings.cpp
test/Sema/uninit-variables.c

index badb493a9df4ede9781f49107065e4b9d52e0adb..e2e4f35043eec209e96e0b38a12d9a9ee04edbdb 100644 (file)
@@ -27,10 +27,16 @@ class UninitVariablesHandler {
 public:
   UninitVariablesHandler() {}
   virtual ~UninitVariablesHandler();
-  
+
+  /// Called when the uninitialized variable is used at the given expression.
   virtual void handleUseOfUninitVariable(const Expr *ex,
                                          const VarDecl *vd,
                                          bool isAlwaysUninit) {}
+  
+  /// Called when the uninitialized variable analysis detects the
+  /// idiom 'int x = x'.  All other uses of 'x' within the initializer
+  /// are handled by handleUseOfUninitVariable.
+  virtual void handleSelfInit(const VarDecl *vd) {}
 };
 
 struct UninitVariablesAnalysisStats {
index 8d48fffe9f265f1793978e9d624aac7446ee6406..9e98560b655dd285df73a58bc6500dac3d01b85c 100644 (file)
@@ -484,11 +484,17 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
               vals[vd] = Uninitialized;
               lastLoad = 0;
               lastDR = 0;
+              if (handler)
+                handler->handleSelfInit(vd);
               return;
             }
           }
 
           // All other cases: treat the new variable as initialized.
+          // This is a minor optimization to reduce the propagation
+          // of the analysis, since we will have already reported
+          // the use of the uninitialized value (which visiting the
+          // initializer).
           vals[vd] = Initialized;
         }
       }
index f461772ba7d4fe6a3be11440dea2cd56086d7033..babb8af18b378da813527b461987277264d6db03 100644 (file)
@@ -470,7 +470,8 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
 /// as a warning. If a pariticular use is one we omit warnings for, returns
 /// false.
 static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
-                                     const Expr *E, bool isAlwaysUninit) {
+                                     const Expr *E, bool isAlwaysUninit,
+                                     bool alwaysReportSelfInit = false) {
   bool isSelfInit = false;
 
   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
@@ -490,7 +491,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
       // TODO: Should we suppress maybe-uninitialized warnings for
       // variables initialized in this way?
       if (const Expr *Initializer = VD->getInit()) {
-        if (DRE == Initializer->IgnoreParenImpCasts())
+        if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
           return false;
 
         ContainsReference CR(S.Context, DRE);
@@ -541,7 +542,7 @@ struct SLocSort {
 class UninitValsDiagReporter : public UninitVariablesHandler {
   Sema &S;
   typedef SmallVector<UninitUse, 2> UsesVec;
-  typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap;
+  typedef llvm::DenseMap<const VarDecl *, std::pair<UsesVec*, bool> > UsesMap;
   UsesMap *uses;
   
 public:
@@ -549,17 +550,26 @@ public:
   ~UninitValsDiagReporter() { 
     flushDiagnostics();
   }
-  
-  void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd,
-                                 bool isAlwaysUninit) {
+
+  std::pair<UsesVec*, bool> &getUses(const VarDecl *vd) {
     if (!uses)
       uses = new UsesMap();
-    
-    UsesVec *&vec = (*uses)[vd];
+
+    UsesMap::mapped_type &V = (*uses)[vd];
+    UsesVec *&vec = V.first;
     if (!vec)
       vec = new UsesVec();
     
-    vec->push_back(std::make_pair(ex, isAlwaysUninit));
+    return V;
+  }
+  
+  void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd,
+                                 bool isAlwaysUninit) {
+    getUses(vd).first->push_back(std::make_pair(ex, isAlwaysUninit));
+  }
+  
+  void handleSelfInit(const VarDecl *vd) {
+    getUses(vd).second = true;    
   }
   
   void flushDiagnostics() {
@@ -568,22 +578,34 @@ public:
     
     for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) {
       const VarDecl *vd = i->first;
-      UsesVec *vec = i->second;
-
-      // Sort the uses by their SourceLocations.  While not strictly
-      // guaranteed to produce them in line/column order, this will provide
-      // a stable ordering.
-      std::sort(vec->begin(), vec->end(), SLocSort());
-      
-      for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve;
-           ++vi) {
-        if (DiagnoseUninitializedUse(S, vd, vi->first,
-                                      /*isAlwaysUninit=*/vi->second))
-          // Skip further diagnostics for this variable. We try to warn only on
-          // the first point at which a variable is used uninitialized.
-          break;
+      const UsesMap::mapped_type &V = i->second;
+
+      UsesVec *vec = V.first;
+      bool hasSelfInit = V.second;
+
+      // Specially handle the case where we have uses of an uninitialized 
+      // variable, but the root cause is an idiomatic self-init.  We want
+      // to report the diagnostic at the self-init since that is the root cause.
+      if (!vec->empty() && hasSelfInit)
+        DiagnoseUninitializedUse(S, vd, vd->getInit()->IgnoreParenCasts(),
+                                 true, /* alwaysReportSelfInit */ true);
+      else {
+        // Sort the uses by their SourceLocations.  While not strictly
+        // guaranteed to produce them in line/column order, this will provide
+        // a stable ordering.
+        std::sort(vec->begin(), vec->end(), SLocSort());
+        
+        for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve;
+             ++vi) {
+          if (DiagnoseUninitializedUse(S, vd, vi->first,
+                                        /*isAlwaysUninit=*/vi->second))
+            // Skip further diagnostics for this variable. We try to warn only
+            // on the first point at which a variable is used uninitialized.
+            break;
+        }
       }
-
+      
+      // Release the uses vector.
       delete vec;
     }
     delete uses;
index f716124bcbbb86d1da519a728c6ec2f9b158c7ef..49af4f32262959e855c015bb5105ce4aa08b3661 100644 (file)
@@ -94,10 +94,15 @@ void test14() {
   for (;;) {}
 }
 
-int test15() {
-  int x = x; // no-warning: signals intended lack of initialization. \
-             // expected-note{{variable 'x' is declared here}}
-  return x; // expected-warning{{variable 'x' is uninitialized when used here}}
+void test15() {
+  int x = x; // no-warning: signals intended lack of initialization.
+}
+
+int test15b() {
+  // Warn here with the self-init, since it does result in a use of
+  // an unintialized variable and this is the root cause.
+  int x = x; // expected-warning {{variable 'x' is uninitialized when used within its own initialization}}
+  return x;
 }
 
 // Don't warn in the following example; shows dataflow confluence.