rtrieu created this revision.

Improve some diagnostics around self-initialization.  The uninitialized checker 
does not warn on self-initialization, but does warn later if the variable is 
used.  GCC also has a -Winit-self which will enable a -Wuninitialized warning 
for self-initialized.  -Winit-self is active in -Wall

There's also the matter of the variable being const.  GCC -Wuninitialized will 
warn on a const self-initialized with or without -Winit-self.

This patch will make it so that const self-initialization is always warned on 
under -Wuninitialized.  Since Clang does not use warning flags to control other 
warnings, -Winit-self will be a new warning group for non-const 
self-initialized.  -Winit-self will also be in -Wall via -Wmost.

  // GCC - warn with -Wuninitialized and -Winit-self
  // Clang - no warning
  // Clang with patch - warn with -Winit-self
  void f1() {
    int x = x;
  }
  
  // GCC - warn with -Wuninitialized
  // Clang - no warning
  // Clang with patch - warn with -Wuninitialized
  void f2() {
    const int x = x;
  }




https://reviews.llvm.org/D52218

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/AnalysisBasedWarnings.cpp
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/uninitialized.cpp

Index: test/SemaCXX/uninitialized.cpp
===================================================================
--- test/SemaCXX/uninitialized.cpp
+++ test/SemaCXX/uninitialized.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -Wno-unused-value -Wno-unused-lambda-capture -std=c++1z -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -Wno-unused -std=c++1z -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wall -Wno-unused -Wno-init-self -std=c++1z -verify %s
 
 // definitions for std::move
 namespace std {
@@ -1432,7 +1433,7 @@
 void array_capture(bool b) {
   const char fname[] = "array_capture";
   if (b) {
-    int unused; // expected-warning {{unused variable}}
+    int unused;
   } else {
     [fname]{};
   }
@@ -1447,3 +1448,15 @@
 
   switch (int n; (n == k || k > 5)) {} // expected-warning {{uninitialized}} expected-note {{initialize}} expected-warning {{boolean}}
 }
+
+namespace const_self_init {
+const int a = a;  // no-warning for global
+
+void const_init() {
+  const int a = a; // expected-warning {{variable 'a' is uninitialized when used within its own initialization}}
+
+  const int b = b; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}}
+  int c = b;
+}
+
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11111,6 +11111,19 @@
     Init = Result.getAs<Expr>();
   }
 
+  if (!VDecl->getType().isConstQualified()) {
+    if (auto *SubExpr = dyn_cast<ImplicitCastExpr>(Init->IgnoreParens())) {
+      if (SubExpr->getCastKind() == CK_LValueToRValue) {
+        if (auto *DRE = dyn_cast<DeclRefExpr>(SubExpr->getSubExpr())) {
+          if (DRE->getDecl() == VDecl) {
+            Diag(VDecl->getLocation(), diag::warn_uninit_self_init)
+                << VDecl << VDecl->getSourceRange() << DRE->getSourceRange();
+          }
+        }
+      }
+    }
+  }
+
   // Check for self-references within variable initializers.
   // Variables declared within a function/method body (except for references)
   // are handled by a dataflow analysis.
Index: lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- lib/Sema/AnalysisBasedWarnings.cpp
+++ lib/Sema/AnalysisBasedWarnings.cpp
@@ -977,7 +977,8 @@
     // uninitialized. Proven code paths which access 'x' in
     // an uninitialized state after this will still warn.
     if (const Expr *Initializer = VD->getInit()) {
-      if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts())
+      if (!VD->getType().isConstQualified() && !alwaysReportSelfInit &&
+          DRE == Initializer->IgnoreParenImpCasts())
         return false;
 
       ContainsReference CR(S.Context, DRE);
@@ -1518,10 +1519,17 @@
       UsesVec *vec = V.getPointer();
       bool hasSelfInit = V.getInt();
 
-      // 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 && hasAlwaysUninitializedUse(vec))
+      if (hasSelfInit && vd->getType().isConstQualified()) {
+        // Handle "const int a = a;"
+        DiagnoseUninitializedUse(S, vd,
+                                 UninitUse(vd->getInit()->IgnoreParenCasts(),
+                                           /* isAlwaysUninit */ true),
+                                 /* alwaysReportSelfInit */ true);
+      } else if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
+        // 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.
         DiagnoseUninitializedUse(S, vd,
                                  UninitUse(vd->getInit()->IgnoreParenCasts(),
                                            /* isAlwaysUninit */ true),
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1907,6 +1907,8 @@
 def warn_uninit_self_reference_in_init : Warning<
   "variable %0 is uninitialized when used within its own initialization">,
   InGroup<Uninitialized>;
+def warn_uninit_self_init : Warning<"variable %0 is initialized with itself">,
+  InGroup<InitSelf>, DefaultIgnore;
 def warn_uninit_self_reference_in_reference_init : Warning<
   "reference %0 is not yet bound to a value when used within its own"
   " initialization">,
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -311,7 +311,7 @@
 def InvalidNoreturn : DiagGroup<"invalid-noreturn">;
 def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">;
 def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
-def : DiagGroup<"init-self">;
+def InitSelf : DiagGroup<"init-self">;
 def : DiagGroup<"inline">;
 def : DiagGroup<"invalid-pch">;
 def GNULabelsAsValue : DiagGroup<"gnu-label-as-value">;
@@ -775,6 +775,7 @@
     Format,
     Implicit,
     InfiniteRecursion,
+    InitSelf,
     MismatchedTags,
     MissingBraces,
     Move,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to