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