[clang] Fix suppressing diagnostics for uninitialized variables (#148336)
When one kind of diagnostics is disabled, this should not preclude other diagnostics from displaying, even if they have lower priority. For example, this should print a warning about passing an uninitialized variable as a const reference: ``` > cat test.cpp void foo(const int &); int f(bool a) { int v; if (a) { foo(v); v = 5; } return v; } > clang test.cpp -fsyntax-only -Wuninitialized -Wno-sometimes-uninitialized ```
This commit is contained in:
parent
ada514b0af
commit
2464313eef
@ -987,10 +987,11 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Diagnose uninitialized const reference usages.
|
/// Diagnose uninitialized const reference usages.
|
||||||
static void DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
|
static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
|
||||||
const UninitUse &Use) {
|
const UninitUse &Use) {
|
||||||
S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference)
|
S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference)
|
||||||
<< VD->getDeclName() << Use.getUser()->getSourceRange();
|
<< VD->getDeclName() << Use.getUser()->getSourceRange();
|
||||||
|
return !S.getDiagnostics().isLastDiagnosticIgnored();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
|
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
|
||||||
@ -1022,7 +1023,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
|
|||||||
if (CR.doesContainReference()) {
|
if (CR.doesContainReference()) {
|
||||||
S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
|
S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
|
||||||
<< VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
|
<< VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
|
||||||
return true;
|
return !S.getDiagnostics().isLastDiagnosticIgnored();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1045,7 +1046,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
|
|||||||
S.Diag(VD->getBeginLoc(), diag::note_var_declared_here)
|
S.Diag(VD->getBeginLoc(), diag::note_var_declared_here)
|
||||||
<< VD->getDeclName();
|
<< VD->getDeclName();
|
||||||
|
|
||||||
return true;
|
return !S.getDiagnostics().isLastDiagnosticIgnored();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -1559,43 +1560,7 @@ public:
|
|||||||
UsesVec *vec = V.getPointer();
|
UsesVec *vec = V.getPointer();
|
||||||
bool hasSelfInit = V.getInt();
|
bool hasSelfInit = V.getInt();
|
||||||
|
|
||||||
// Specially handle the case where we have uses of an uninitialized
|
diagnoseUnitializedVar(vd, hasSelfInit, vec);
|
||||||
// variable, but the root cause is an idiomatic self-init. We want
|
|
||||||
// to report the diagnostic at the self-init since that is the root cause.
|
|
||||||
if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
|
|
||||||
DiagnoseUninitializedUse(S, vd,
|
|
||||||
UninitUse(vd->getInit()->IgnoreParenCasts(),
|
|
||||||
/* isAlwaysUninit */ true),
|
|
||||||
/* alwaysReportSelfInit */ true);
|
|
||||||
else {
|
|
||||||
// Sort the uses by their SourceLocations. While not strictly
|
|
||||||
// guaranteed to produce them in line/column order, this will provide
|
|
||||||
// a stable ordering.
|
|
||||||
llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
|
|
||||||
// Move ConstRef uses to the back.
|
|
||||||
if (a.isConstRefUse() != b.isConstRefUse())
|
|
||||||
return b.isConstRefUse();
|
|
||||||
// Prefer a more confident report over a less confident one.
|
|
||||||
if (a.getKind() != b.getKind())
|
|
||||||
return a.getKind() > b.getKind();
|
|
||||||
return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const auto &U : *vec) {
|
|
||||||
if (U.isConstRefUse()) {
|
|
||||||
DiagnoseUninitializedConstRefUse(S, vd, U);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have self-init, downgrade all uses to 'may be uninitialized'.
|
|
||||||
UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
|
|
||||||
|
|
||||||
if (DiagnoseUninitializedUse(S, vd, Use))
|
|
||||||
// Skip further diagnostics for this variable. We try to warn only
|
|
||||||
// on the first point at which a variable is used uninitialized.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the uses vector.
|
// Release the uses vector.
|
||||||
delete vec;
|
delete vec;
|
||||||
@ -1612,6 +1577,49 @@ private:
|
|||||||
U.getKind() == UninitUse::AfterDecl;
|
U.getKind() == UninitUse::AfterDecl;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print the diagnostic for the variable. We try to warn only on the first
|
||||||
|
// point at which a variable is used uninitialized. After the first
|
||||||
|
// diagnostic is printed, further diagnostics for this variable are skipped.
|
||||||
|
void diagnoseUnitializedVar(const VarDecl *vd, bool hasSelfInit,
|
||||||
|
UsesVec *vec) {
|
||||||
|
// Specially handle the case where we have uses of an uninitialized
|
||||||
|
// variable, but the root cause is an idiomatic self-init. We want
|
||||||
|
// to report the diagnostic at the self-init since that is the root cause.
|
||||||
|
if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
|
||||||
|
if (DiagnoseUninitializedUse(S, vd,
|
||||||
|
UninitUse(vd->getInit()->IgnoreParenCasts(),
|
||||||
|
/*isAlwaysUninit=*/true),
|
||||||
|
/*alwaysReportSelfInit=*/true))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the uses by their SourceLocations. While not strictly
|
||||||
|
// guaranteed to produce them in line/column order, this will provide
|
||||||
|
// a stable ordering.
|
||||||
|
llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
|
||||||
|
// Prefer the direct use of an uninitialized variable over its use via
|
||||||
|
// constant reference.
|
||||||
|
if (a.isConstRefUse() != b.isConstRefUse())
|
||||||
|
return b.isConstRefUse();
|
||||||
|
// Prefer a more confident report over a less confident one.
|
||||||
|
if (a.getKind() != b.getKind())
|
||||||
|
return a.getKind() > b.getKind();
|
||||||
|
return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const auto &U : *vec) {
|
||||||
|
if (U.isConstRefUse()) {
|
||||||
|
if (DiagnoseUninitializedConstRefUse(S, vd, U))
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// If we have self-init, downgrade all uses to 'may be uninitialized'.
|
||||||
|
UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
|
||||||
|
if (DiagnoseUninitializedUse(S, vd, Use))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Inter-procedural data for the called-once checker.
|
/// Inter-procedural data for the called-once checker.
|
||||||
|
12
clang/test/SemaCXX/warn-no-sometimes-uninitialized.cpp
Normal file
12
clang/test/SemaCXX/warn-no-sometimes-uninitialized.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -Wno-sometimes-uninitialized -verify %s
|
||||||
|
|
||||||
|
void foo(const int &);
|
||||||
|
|
||||||
|
int f(bool a) {
|
||||||
|
int v;
|
||||||
|
if (a) {
|
||||||
|
foo(v); // expected-warning {{variable 'v' is uninitialized when passed as a const reference argument here}}
|
||||||
|
v = 5;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user