diff options
| author | Chandler Carruth <chandlerc@gmail.com> | 2011-04-05 17:41:31 +0000 |
|---|---|---|
| committer | Chandler Carruth <chandlerc@gmail.com> | 2011-04-05 17:41:31 +0000 |
| commit | b5d4831f8372120a5b1aef14a8add2a0691f3977 (patch) | |
| tree | 3d4cb79f6bd789a8d1658acea956929dc2f59768 | |
| parent | 7522abd3ce7c24c27c9c9fbe2edec63962157ab2 (diff) | |
| download | bcm5719-llvm-b5d4831f8372120a5b1aef14a8add2a0691f3977.tar.gz bcm5719-llvm-b5d4831f8372120a5b1aef14a8add2a0691f3977.zip | |
Fix PR9624 by explicitly disabling uninitialized warnings for direct self-init:
int x = x;
GCC disables its warnings on this construct as a way of indicating that
the programmer intentionally wants the variable to be uninitialized.
Only the warning on the initializer is turned off in this iteration.
This makes the code a lot more ugly, but starts commenting the
surprising behavior here. This is a WIP, I want to refactor it
substantially for clarity, and to determine whether subsequent warnings
should be suppressed or not.
llvm-svn: 128894
| -rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 45 | ||||
| -rw-r--r-- | clang/test/Sema/uninit-variables.c | 2 | ||||
| -rw-r--r-- | clang/test/SemaCXX/uninitialized.cpp | 2 |
3 files changed, 30 insertions, 19 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index efb71baddbc..df73fc6da3a 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -410,16 +410,6 @@ public: }; } -static bool isSelfInit(ASTContext &Context, - const VarDecl *VD, const DeclRefExpr *DR) { - if (const Expr *E = VD->getInit()) { - ContainsReference CR(Context, DR); - CR.Visit(const_cast<Expr*>(E)); - return CR.doesContainReference(); - } - return false; -} - typedef std::pair<const Expr*, bool> UninitUse; namespace { @@ -473,17 +463,37 @@ public: for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi) { const bool isAlwaysUninit = vi->second; - bool showDefinition = true; + bool isSelfInit = false; if (const DeclRefExpr *dr = dyn_cast<DeclRefExpr>(vi->first)) { if (isAlwaysUninit) { - if (isSelfInit(S.Context, vd, dr)) { + // Inspect the initializer of the variable declaration which is + // being referenced prior to its initialization. We emit + // specialized diagnostics for self-initialization, and we + // specifically avoid warning about self references which take the + // form of: + // + // int x = x; + // + // This is used to indicate to GCC that 'x' is intentionally left + // uninitialized. Proven code paths which access 'x' in + // an uninitialized state after this will still warn. + // + // TODO: Should we suppress maybe-uninitialized warnings for + // variables initialized in this way? + if (const Expr *E = vd->getInit()) { + if (dr == E->IgnoreParenImpCasts()) + continue; + + ContainsReference CR(S.Context, dr); + CR.Visit(const_cast<Expr*>(E)); + isSelfInit = CR.doesContainReference(); + } + if (isSelfInit) { S.Diag(dr->getLocStart(), diag::warn_uninit_self_reference_in_init) << vd->getDeclName() << vd->getLocation() << dr->getSourceRange(); - showDefinition = false; - } - else { + } else { S.Diag(dr->getLocStart(), diag::warn_uninit_var) << vd->getDeclName() << dr->getSourceRange(); } @@ -501,8 +511,9 @@ public: << vd->getDeclName(); } - // Report where the variable was declared. - if (showDefinition) + // Report where the variable was declared when the use wasn't within + // the initializer of that declaration. + if (!isSelfInit) S.Diag(vd->getLocStart(), diag::note_uninit_var_def) << vd->getDeclName(); diff --git a/clang/test/Sema/uninit-variables.c b/clang/test/Sema/uninit-variables.c index 330444bb5c4..ee3e88a49c8 100644 --- a/clang/test/Sema/uninit-variables.c +++ b/clang/test/Sema/uninit-variables.c @@ -92,7 +92,7 @@ void test14() { } void test15() { - int x = x; // expected-warning{{variable 'x' is uninitialized when used within its own initialization}} + int x = x; // no-warning: signals intended lack of initialization. } // Don't warn in the following example; shows dataflow confluence. diff --git a/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp index cf75187ab8e..0a3b5d938dd 100644 --- a/clang/test/SemaCXX/uninitialized.cpp +++ b/clang/test/SemaCXX/uninitialized.cpp @@ -7,7 +7,7 @@ int far(const int& x); // Test self-references within initializers which are guaranteed to be // uninitialized. -int a = a; // FIXME: This doesn't warn!? Seems it doesn't cast 'a' to an RValue. +int a = a; // no-warning: used to signal intended lack of initialization. int b = b + 1; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}} int c = (c + c); // expected-warning 2 {{variable 'c' is uninitialized when used within its own initialization}} void test() { |

