Add a warning on variable initialization which references its own value.
 Non-evaluated expressions, such as address of or size of operations, are
not warned on.
Index: test/Preprocessor/pragma_diagnostic_sections.cpp
===================================================================
--- test/Preprocessor/pragma_diagnostic_sections.cpp	(revision 128110)
+++ test/Preprocessor/pragma_diagnostic_sections.cpp	(working copy)
@@ -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 @@
 #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
 
Index: test/SemaCXX/init-self-reference.cpp
===================================================================
--- test/SemaCXX/init-self-reference.cpp	(revision 0)
+++ test/SemaCXX/init-self-reference.cpp	(revision 0)
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -ffreestanding
+
+int foo(int x);
+int bar(int* x);
+int boo(int& x);
+int far(const int& x);
+int a = a + 1;  // expected-warning {{variable 'a' is used (uninitialized) within its own initialization}}
+int b = bar(&b);
+int c = foo(c);  // expected-warning {{variable 'c' is used (uninitialized) within its own initialization}}
+int d = sizeof(d);
+void* ptr = &ptr;
+double e = 1.003 * (23 / (.0004 - (e)));  // expected-warning {{variable 'e' is used (uninitialized) within its own initialization}}
+float f = 1 + (((((f)))));  // expected-warning {{variable 'f' is used (uninitialized) within its own initialization}}
+int g = (g + g);  // expected-warning 2{{variable 'g' is used (uninitialized) within its own initialization}}
+int h = boo(h);
+int i = far(i);
+int j = __alignof__(j);
+void test() {
+  int k = ({ k + k ;});  // expected-warning 2{{variable 'k' is used (uninitialized) within its own initialization}}
+}
+int l = static_cast<long>(l) + 1;  // expected-warning {{variable 'l' is used (uninitialized) within its own initialization}}
Index: test/PCH/rdar8852495.c
===================================================================
--- test/PCH/rdar8852495.c	(revision 128110)
+++ test/PCH/rdar8852495.c	(working copy)
@@ -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: test/PCH/pragma-diag.c
===================================================================
--- test/PCH/pragma-diag.c	(revision 128110)
+++ test/PCH/pragma-diag.c	(working copy)
@@ -13,7 +13,8 @@
 #else
 
 void f() {
-  int b = b==b;
+  int a = 0;
+  int b = a==a;
 }
 
 #endif
Index: test/PCH/pragma-diag-section.cpp
===================================================================
--- test/PCH/pragma-diag-section.cpp	(revision 128110)
+++ test/PCH/pragma-diag-section.cpp	(working copy)
@@ -12,7 +12,9 @@
 #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: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 128110)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -2226,6 +2226,8 @@
 def warn_anon_bitfield_width_exceeds_type_size : Warning<
   "size of anonymous bit-field (%0 bits) exceeds size of its type; value will "
   "be truncated to %1 bits">;
+def warn_self_reference_in_init : Warning<
+  "variable %0 is used (uninitialized) within its own initialization">;
 
 def warn_missing_braces : Warning<
   "suggest braces around initialization of subobject">,
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 128110)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -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"
@@ -673,7 +674,7 @@
 
   if (isa<LabelDecl>(D))
     return true;
-  
+
   // White-list anything that isn't a local variable.
   if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ||
       !D->getDeclContext()->isFunctionOrMethod())
@@ -763,7 +764,7 @@
     // If this was a forward reference to a label, verify it was defined.
     if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
       CheckPoppedLabel(LD, *this);
-    
+
     // Remove this name from our lexical scope.
     IdResolver.RemoveDecl(D);
   }
@@ -4627,6 +4628,46 @@
   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_self_reference_in_init)
+        << Result.getLookupName() << OrigDecl->getSourceRange()
+        << SubExpr->getSourceRange();
+    }
+  };
+}
+
 /// AddInitializerToDecl - Adds the initializer Init to the
 /// declaration dcl. If DirectInit is true, this is C++ direct
 /// initialization rather than copy initialization.
@@ -4637,6 +4678,8 @@
   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.
@@ -5194,7 +5237,7 @@
     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);
 }
 
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to