Skip to content

Commit 2464313

Browse files
authored
[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 ```
1 parent ada514b commit 2464313

File tree

2 files changed

+60
-40
lines changed

2 files changed

+60
-40
lines changed

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -987,10 +987,11 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
987987
}
988988

989989
/// Diagnose uninitialized const reference usages.
990-
static void DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
990+
static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
991991
const UninitUse &Use) {
992992
S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference)
993993
<< VD->getDeclName() << Use.getUser()->getSourceRange();
994+
return !S.getDiagnostics().isLastDiagnosticIgnored();
994995
}
995996

996997
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
@@ -1022,7 +1023,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
10221023
if (CR.doesContainReference()) {
10231024
S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init)
10241025
<< VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
1025-
return true;
1026+
return !S.getDiagnostics().isLastDiagnosticIgnored();
10261027
}
10271028
}
10281029

@@ -1045,7 +1046,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
10451046
S.Diag(VD->getBeginLoc(), diag::note_var_declared_here)
10461047
<< VD->getDeclName();
10471048

1048-
return true;
1049+
return !S.getDiagnostics().isLastDiagnosticIgnored();
10491050
}
10501051

10511052
namespace {
@@ -1559,43 +1560,7 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
15591560
UsesVec *vec = V.getPointer();
15601561
bool hasSelfInit = V.getInt();
15611562

1562-
// Specially handle the case where we have uses of an uninitialized
1563-
// variable, but the root cause is an idiomatic self-init. We want
1564-
// to report the diagnostic at the self-init since that is the root cause.
1565-
if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
1566-
DiagnoseUninitializedUse(S, vd,
1567-
UninitUse(vd->getInit()->IgnoreParenCasts(),
1568-
/* isAlwaysUninit */ true),
1569-
/* alwaysReportSelfInit */ true);
1570-
else {
1571-
// Sort the uses by their SourceLocations. While not strictly
1572-
// guaranteed to produce them in line/column order, this will provide
1573-
// a stable ordering.
1574-
llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
1575-
// Move ConstRef uses to the back.
1576-
if (a.isConstRefUse() != b.isConstRefUse())
1577-
return b.isConstRefUse();
1578-
// Prefer a more confident report over a less confident one.
1579-
if (a.getKind() != b.getKind())
1580-
return a.getKind() > b.getKind();
1581-
return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc();
1582-
});
1583-
1584-
for (const auto &U : *vec) {
1585-
if (U.isConstRefUse()) {
1586-
DiagnoseUninitializedConstRefUse(S, vd, U);
1587-
break;
1588-
}
1589-
1590-
// If we have self-init, downgrade all uses to 'may be uninitialized'.
1591-
UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
1592-
1593-
if (DiagnoseUninitializedUse(S, vd, Use))
1594-
// Skip further diagnostics for this variable. We try to warn only
1595-
// on the first point at which a variable is used uninitialized.
1596-
break;
1597-
}
1598-
}
1563+
diagnoseUnitializedVar(vd, hasSelfInit, vec);
15991564

16001565
// Release the uses vector.
16011566
delete vec;
@@ -1612,6 +1577,49 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
16121577
U.getKind() == UninitUse::AfterDecl;
16131578
});
16141579
}
1580+
1581+
// Print the diagnostic for the variable. We try to warn only on the first
1582+
// point at which a variable is used uninitialized. After the first
1583+
// diagnostic is printed, further diagnostics for this variable are skipped.
1584+
void diagnoseUnitializedVar(const VarDecl *vd, bool hasSelfInit,
1585+
UsesVec *vec) {
1586+
// Specially handle the case where we have uses of an uninitialized
1587+
// variable, but the root cause is an idiomatic self-init. We want
1588+
// to report the diagnostic at the self-init since that is the root cause.
1589+
if (hasSelfInit && hasAlwaysUninitializedUse(vec)) {
1590+
if (DiagnoseUninitializedUse(S, vd,
1591+
UninitUse(vd->getInit()->IgnoreParenCasts(),
1592+
/*isAlwaysUninit=*/true),
1593+
/*alwaysReportSelfInit=*/true))
1594+
return;
1595+
}
1596+
1597+
// Sort the uses by their SourceLocations. While not strictly
1598+
// guaranteed to produce them in line/column order, this will provide
1599+
// a stable ordering.
1600+
llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
1601+
// Prefer the direct use of an uninitialized variable over its use via
1602+
// constant reference.
1603+
if (a.isConstRefUse() != b.isConstRefUse())
1604+
return b.isConstRefUse();
1605+
// Prefer a more confident report over a less confident one.
1606+
if (a.getKind() != b.getKind())
1607+
return a.getKind() > b.getKind();
1608+
return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc();
1609+
});
1610+
1611+
for (const auto &U : *vec) {
1612+
if (U.isConstRefUse()) {
1613+
if (DiagnoseUninitializedConstRefUse(S, vd, U))
1614+
return;
1615+
} else {
1616+
// If we have self-init, downgrade all uses to 'may be uninitialized'.
1617+
UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
1618+
if (DiagnoseUninitializedUse(S, vd, Use))
1619+
return;
1620+
}
1621+
}
1622+
}
16151623
};
16161624

16171625
/// Inter-procedural data for the called-once checker.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -Wno-sometimes-uninitialized -verify %s
2+
3+
void foo(const int &);
4+
5+
int f(bool a) {
6+
int v;
7+
if (a) {
8+
foo(v); // expected-warning {{variable 'v' is uninitialized when passed as a const reference argument here}}
9+
v = 5;
10+
}
11+
return v;
12+
}

0 commit comments

Comments
 (0)