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
This commit is contained in:
Chandler Carruth 2011-04-05 17:41:31 +00:00
parent 7522abd3ce
commit b5d4831f83
3 changed files with 30 additions and 19 deletions

View File

@ -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();

View File

@ -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.

View File

@ -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() {