diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 45 | ||||
-rw-r--r-- | test/PCH/pragma-diag-section.cpp | 5 | ||||
-rw-r--r-- | test/PCH/pragma-diag.c | 3 | ||||
-rw-r--r-- | test/PCH/rdar8852495.c | 3 | ||||
-rw-r--r-- | test/Preprocessor/pragma_diagnostic_sections.cpp | 8 |
6 files changed, 59 insertions, 8 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 55223ac134..6e0bec2f1f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 : diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 59b4f5f229..7a1492a53b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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); } diff --git a/test/PCH/pragma-diag-section.cpp b/test/PCH/pragma-diag-section.cpp index 312f720ebd..5b996bb2f0 100644 --- a/test/PCH/pragma-diag-section.cpp +++ b/test/PCH/pragma-diag-section.cpp @@ -12,7 +12,10 @@ #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 diff --git a/test/PCH/pragma-diag.c b/test/PCH/pragma-diag.c index c517103640..b304c4bf8c 100644 --- a/test/PCH/pragma-diag.c +++ b/test/PCH/pragma-diag.c @@ -13,7 +13,8 @@ #else void f() { - int b = b==b; + int a = 0; + int b = a==a; } #endif diff --git a/test/PCH/rdar8852495.c b/test/PCH/rdar8852495.c index 2d49e001b0..fb465a37ce 100644 --- a/test/PCH/rdar8852495.c +++ b/test/PCH/rdar8852495.c @@ -16,7 +16,8 @@ #else int f() { - int b = b==b; + int a; + int b = a==a; unsigned x; signed y; return x == y; diff --git a/test/Preprocessor/pragma_diagnostic_sections.cpp b/test/Preprocessor/pragma_diagnostic_sections.cpp index 69436b0bd8..b680fae5b9 100644 --- a/test/Preprocessor/pragma_diagnostic_sections.cpp +++ b/test/Preprocessor/pragma_diagnostic_sections.cpp @@ -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 |