]> granicus.if.org Git - clang/commitdiff
Fix PR9624 by explicitly disabling uninitialized warnings for direct self-init:
authorChandler Carruth <chandlerc@gmail.com>
Tue, 5 Apr 2011 17:41:31 +0000 (17:41 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Tue, 5 Apr 2011 17:41:31 +0000 (17:41 +0000)
  int x = x;

GCC disables its warnings on this construct as a way of indicating that
the programmer intentionally wants the variable to be uninitialized.
Only the warning on the initializer is turned off in this iteration.

This makes the code a lot more ugly, but starts commenting the
surprising behavior here. This is a WIP, I want to refactor it
substantially for clarity, and to determine whether subsequent warnings
should be suppressed or not.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128894 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/AnalysisBasedWarnings.cpp
test/Sema/uninit-variables.c
test/SemaCXX/uninitialized.cpp

index efb71baddbceb99be716ea04c9d137070a74e473..df73fc6da3a74dd1c771239c94370a0c4955e5be 100644 (file)
@@ -410,16 +410,6 @@ public:
 };
 }
 
-static bool isSelfInit(ASTContext &Context,
-                       const VarDecl *VD, const DeclRefExpr *DR) {
-  if (const Expr *E = VD->getInit()) {
-    ContainsReference CR(Context, DR);
-    CR.Visit(const_cast<Expr*>(E));
-    return CR.doesContainReference();
-  }
-  return false;
-}
-
 typedef std::pair<const Expr*, bool> UninitUse;
 
 namespace {
@@ -473,17 +463,37 @@ public:
       for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi)
       {
         const bool isAlwaysUninit = vi->second;
-        bool showDefinition = true;
+        bool isSelfInit = false;
 
         if (const DeclRefExpr *dr = dyn_cast<DeclRefExpr>(vi->first)) {
           if (isAlwaysUninit) {
-            if (isSelfInit(S.Context, vd, dr)) {
+            // Inspect the initializer of the variable declaration which is
+            // being referenced prior to its initialization. We emit
+            // specialized diagnostics for self-initialization, and we
+            // specifically avoid warning about self references which take the
+            // form of:
+            //
+            //   int x = x;
+            //
+            // This is used to indicate to GCC that 'x' is intentionally left
+            // uninitialized. Proven code paths which access 'x' in
+            // an uninitialized state after this will still warn.
+            //
+            // TODO: Should we suppress maybe-uninitialized warnings for
+            // variables initialized in this way?
+            if (const Expr *E = vd->getInit()) {
+              if (dr == E->IgnoreParenImpCasts())
+                continue;
+
+              ContainsReference CR(S.Context, dr);
+              CR.Visit(const_cast<Expr*>(E));
+              isSelfInit = CR.doesContainReference();
+            }
+            if (isSelfInit) {
               S.Diag(dr->getLocStart(), 
                      diag::warn_uninit_self_reference_in_init)
               << vd->getDeclName() << vd->getLocation() << dr->getSourceRange();             
-              showDefinition = false;
-            }
-            else {
+            } else {
               S.Diag(dr->getLocStart(), diag::warn_uninit_var)
                 << vd->getDeclName() << dr->getSourceRange();          
             }
@@ -501,8 +511,9 @@ public:
             << vd->getDeclName();
         }
         
-        // Report where the variable was declared.
-        if (showDefinition)
+        // Report where the variable was declared when the use wasn't within
+        // the initializer of that declaration.
+        if (!isSelfInit)
           S.Diag(vd->getLocStart(), diag::note_uninit_var_def)
             << vd->getDeclName();
 
index 330444bb5c4703b40ebbb4e611067208c078d911..ee3e88a49c8b92244339c94bd30fb520f9a03a70 100644 (file)
@@ -92,7 +92,7 @@ void test14() {
 }
 
 void test15() {
-  int x = x; // expected-warning{{variable 'x' is uninitialized when used within its own initialization}}
+  int x = x; // no-warning: signals intended lack of initialization.
 }
 
 // Don't warn in the following example; shows dataflow confluence.
index cf75187ab8e16cec6b5f4f0cdf4d5280def209a9..0a3b5d938dd333125cf391757a7f2b48403e2cf0 100644 (file)
@@ -7,7 +7,7 @@ int far(const int& x);
 
 // Test self-references within initializers which are guaranteed to be
 // uninitialized.
-int a = a; // FIXME: This doesn't warn!? Seems it doesn't cast 'a' to an RValue.
+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}}
 int c = (c + c); // expected-warning 2 {{variable 'c' is uninitialized when used within its own initialization}}
 void test() {