]> granicus.if.org Git - clang/commitdiff
Diagnose uninitialized uses of a variable within its own initializer.
authorChandler Carruth <chandlerc@gmail.com>
Sun, 27 Mar 2011 09:46:56 +0000 (09:46 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sun, 27 Mar 2011 09:46:56 +0000 (09:46 +0000)
This is basically the same idea as the warning on uninitialized uses of
fields within an initializer list. As such, it is on by default and
under -Wuninitialized.

Original patch by Richard Trieu, with some massaging from me on the
wording and grouping of the diagnostics.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
test/PCH/pragma-diag-section.cpp
test/PCH/pragma-diag.c
test/PCH/rdar8852495.c
test/Preprocessor/pragma_diagnostic_sections.cpp

index 55223ac134351d3e3a2a4fd596ca960af2d84894..6e0bec2f1fe4f24d16ee34d4ed413e8b99bf2e58 100644 (file)
@@ -871,6 +871,9 @@ def note_uninit_reference_member : Note<
   "uninitialized reference member is here">;
 def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
   InGroup<Uninitialized>;
+def warn_uninit_self_reference_in_init : Warning<
+  "variable %0 is uninitialized when used within its own initialization">,
+  InGroup<Uninitialized>;
 def warn_uninit_var : Warning<"variable %0 is possibly uninitialized when used here">,
   InGroup<Uninitialized>, DefaultIgnore;
 def warn_maybe_uninit_var :
index 59b4f5f2292f388faf1b5f42826114268fbad3a3..7a1492a53b553f8669125e1f6ed97601847db49c 100644 (file)
@@ -25,6 +25,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/CharUnits.h"
@@ -4664,6 +4665,46 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
   return true;
 }
 
+namespace {
+  // Visits an initialization expression to see if OrigDecl is evaluated in
+  // its own initialization and throws a warning if it does.
+  class SelfReferenceChecker
+      : public EvaluatedExprVisitor<SelfReferenceChecker> {
+    Sema &S;
+    Decl *OrigDecl;
+
+  public:
+    typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
+
+    SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context),
+                                                    S(S), OrigDecl(OrigDecl) { }
+
+    void VisitExpr(Expr *E) {
+      if (isa<ObjCMessageExpr>(*E)) return;
+      Inherited::VisitExpr(E);
+    }
+
+    void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+      CheckForSelfReference(E);
+      Inherited::VisitImplicitCastExpr(E);
+    }
+
+    void CheckForSelfReference(ImplicitCastExpr *E) {
+      if (E->getCastKind() != CK_LValueToRValue) return;
+      Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
+      DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr);
+      if (!DRE) return;
+      Decl* ReferenceDecl = DRE->getDecl();
+      if (OrigDecl != ReferenceDecl) return;
+      LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
+                          Sema::NotForRedeclaration);
+      S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init)
+        << Result.getLookupName() << OrigDecl->getLocation()
+        << SubExpr->getSourceRange();
+    }
+  };
+}
+
 /// AddInitializerToDecl - Adds the initializer Init to the
 /// declaration dcl. If DirectInit is true, this is C++ direct
 /// initialization rather than copy initialization.
@@ -4674,6 +4715,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
   if (RealDecl == 0 || RealDecl->isInvalidDecl())
     return;
 
+  SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
+
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
     // With declarators parsed the way they are, the parser cannot
     // distinguish between a normal initializer and a pure-specifier.
@@ -5231,7 +5274,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
     if (Decl *D = Group[i])
       Decls.push_back(D);
 
-  return BuildDeclaratorGroup(Decls.data(), Decls.size(), 
+  return BuildDeclaratorGroup(Decls.data(), Decls.size(),
                               DS.getTypeSpecType() == DeclSpec::TST_auto);
 }
 
index 312f720ebd987ff41b6a9f0cbf5249246baafd0d..5b996bb2f0d16f438e1301b4f28c0dc6a6469ef6 100644 (file)
 #pragma clang diagnostic ignored "-Wtautological-compare"
 template <typename T>
 struct TS {
-    void m() { T b = b==b; }
+    void m() {
+      T a = 0;
+      T b = a==a;
+    }
 };
 #pragma clang diagnostic pop
 
index c5171036400f35be84f6e1a6ab83a8e02f7d7301..b304c4bf8c35fe7b12701324dcc40b7c74fddff4 100644 (file)
@@ -13,7 +13,8 @@
 #else
 
 void f() {
-  int b = b==b;
+  int a = 0;
+  int b = a==a;
 }
 
 #endif
index 2d49e001b05158c529f18b5b3eacc255ff552fef..fb465a37ce38da00f78ed52cd4f9eba4cfdac532 100644 (file)
@@ -16,7 +16,8 @@
 #else
 
 int f() {
-  int b = b==b;
+  int a;
+  int b = a==a;
   unsigned x;
   signed y;
   return x == y;
index 69436b0bd84e801cdb24e7a1cb7a369077dc9667..b680fae5b993ff498b8887540c0e97b98414bfd1 100644 (file)
@@ -2,14 +2,14 @@
 
 // rdar://8365684
 struct S {
-    void m1() { int b = b==b; } // expected-warning {{always evaluates to true}}
+    void m1() { int b; while (b==b); } // expected-warning {{always evaluates to true}}
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wtautological-compare"
-    void m2() { int b = b==b; }
+    void m2() { int b; while (b==b); }
 #pragma clang diagnostic pop
 
-    void m3() { int b = b==b; } // expected-warning {{always evaluates to true}}
+    void m3() { int b; while (b==b); } // expected-warning {{always evaluates to true}}
 };
 
 //------------------------------------------------------------------------------
@@ -18,7 +18,7 @@ struct S {
 #pragma clang diagnostic ignored "-Wtautological-compare"
 template <typename T>
 struct TS {
-    void m() { T b = b==b; }
+    void m() { T b; while (b==b); }
 };
 #pragma clang diagnostic pop