Skip to content

Commit 705b29b

Browse files
committed
various fixes and refactors
based on review from gh@zwuis - add release note - move Parser::ParseInitializer impl to a source file - remove FlushDiagnostics, favoring open-coded version - DeclForInitializer is now a VarDecl in Sema.h - use certain llvm helpers like all_of and is_contained Signed-off-by: Justin Stitt <[email protected]>
1 parent 4ce7b0c commit 705b29b

File tree

9 files changed

+58
-68
lines changed

9 files changed

+58
-68
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ Attribute Changes in Clang
286286

287287
Improvements to Clang's diagnostics
288288
-----------------------------------
289+
- Clang now suppresses runtime behavior warnings for unreachable code in file-scope
290+
variable initializers, matching the behavior for functions. This prevents false
291+
positives for operations in unreachable branches of constant expressions.
292+
289293
- Added a separate diagnostic group ``-Wfunction-effect-redeclarations``, for the more pedantic
290294
diagnostics for function effects (``[[clang::nonblocking]]`` and ``[[clang::nonallocating]]``).
291295
Moved the warning for a missing (though implied) attribute on a redeclaration into this group.

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5223,32 +5223,7 @@ class Parser : public CodeCompletionHandler {
52235223
/// assignment-expression
52245224
/// '{' ...
52255225
/// \endverbatim
5226-
ExprResult ParseInitializer(Decl *DeclForInitializer = nullptr) {
5227-
// Set DeclForInitializer for file-scope variables.
5228-
// For constexpr references, set it to suppress runtime warnings.
5229-
// For non-constexpr references, don't set it to avoid evaluation issues
5230-
// with self-referencing initializers. Local variables (including local
5231-
// constexpr) should emit runtime warnings.
5232-
if (DeclForInitializer && !Actions.ExprEvalContexts.empty()) {
5233-
if (auto *VD = dyn_cast<VarDecl>(DeclForInitializer)) {
5234-
if (VD->isFileVarDecl()) {
5235-
if (!VD->getType()->isReferenceType() || VD->isConstexpr()) {
5236-
Actions.ExprEvalContexts.back().DeclForInitializer =
5237-
DeclForInitializer;
5238-
}
5239-
}
5240-
}
5241-
}
5242-
5243-
ExprResult init;
5244-
if (Tok.isNot(tok::l_brace)) {
5245-
init = ParseAssignmentExpression();
5246-
} else {
5247-
init = ParseBraceInitializer();
5248-
}
5249-
5250-
return init;
5251-
}
5226+
ExprResult ParseInitializer(Decl *DeclForInitializer = nullptr);
52525227

52535228
/// MayBeDesignationStart - Return true if the current token might be the
52545229
/// start of a designator. If we can tell it is impossible that it is a

clang/include/clang/Sema/AnalysisBasedWarnings.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ class AnalysisBasedWarnings {
6767
Policy PolicyOverrides;
6868
void clearOverrides();
6969

70-
void FlushDiagnostics(SmallVector<clang::sema::PossiblyUnreachableDiag, 4>);
71-
7270
/// \name Statistics
7371
/// @{
7472

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6753,7 +6753,7 @@ class Sema final : public SemaBase {
67536753
/// Declaration for initializer if one is currently being
67546754
/// parsed. Used when an expression has a possibly unreachable
67556755
/// diagnostic to reference the declaration as a whole.
6756-
Decl *DeclForInitializer = nullptr;
6756+
VarDecl *DeclForInitializer = nullptr;
67576757

67586758
/// If we are processing a decltype type, a set of call expressions
67596759
/// for which we have deferred checking the completeness of the return type.

clang/lib/Analysis/AnalysisDeclContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
118118
else if (const auto *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D))
119119
return FunTmpl->getTemplatedDecl()->getBody();
120120
else if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
121-
if (VD->hasGlobalStorage()) {
121+
if (VD->isFileVarDecl()) {
122122
return const_cast<Stmt *>(dyn_cast_or_null<Stmt>(VD->getInit()));
123123
}
124124
}

clang/lib/Parse/ParseInit.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,28 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
581581

582582
return !trailingComma;
583583
}
584+
585+
ExprResult Parser::ParseInitializer(Decl *DeclForInitializer) {
586+
// Set DeclForInitializer for file-scope variables.
587+
// For constexpr references, set it to suppress runtime warnings.
588+
// For non-constexpr references, don't set it to avoid evaluation issues
589+
// with self-referencing initializers. Local variables (including local
590+
// constexpr) should emit runtime warnings.
591+
if (DeclForInitializer && !Actions.ExprEvalContexts.empty()) {
592+
if (auto *VD = dyn_cast<VarDecl>(DeclForInitializer);
593+
VD && VD->isFileVarDecl()) {
594+
if (!VD->getType()->isReferenceType() || VD->isConstexpr()) {
595+
Actions.ExprEvalContexts.back().DeclForInitializer = VD;
596+
}
597+
}
598+
}
599+
600+
ExprResult init;
601+
if (Tok.isNot(tok::l_brace)) {
602+
init = ParseAssignmentExpression();
603+
} else {
604+
init = ParseBraceInitializer();
605+
}
606+
607+
return init;
608+
}

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2724,53 +2724,36 @@ static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) {
27242724
S.Diag(D.Loc, D.PD);
27252725
}
27262726

2727-
void sema::AnalysisBasedWarnings::FlushDiagnostics(
2728-
const SmallVector<clang::sema::PossiblyUnreachableDiag, 4> PUDs) {
2729-
for (const auto &D : PUDs)
2730-
S.Diag(D.Loc, D.PD);
2731-
}
2732-
27332727
void sema::AnalysisBasedWarnings::EmitPossiblyUnreachableDiags(
27342728
AnalysisDeclContext &AC,
27352729
SmallVector<clang::sema::PossiblyUnreachableDiag, 4> PUDs) {
27362730

2737-
if (PUDs.empty()) {
2731+
if (PUDs.empty())
27382732
return;
2739-
}
2740-
2741-
bool Analyzed = false;
27422733

27432734
for (const auto &D : PUDs) {
27442735
for (const Stmt *S : D.Stmts)
27452736
AC.registerForcedBlockExpression(S);
27462737
}
27472738

27482739
if (AC.getCFG()) {
2749-
Analyzed = true;
27502740
for (const auto &D : PUDs) {
2751-
bool AllReachable = true;
2752-
for (const Stmt *St : D.Stmts) {
2753-
const CFGBlock *block = AC.getBlockForRegisteredExpression(St);
2754-
CFGReverseBlockReachabilityAnalysis *cra =
2755-
AC.getCFGReachablityAnalysis();
2756-
if (block && cra) {
2757-
// Can this block be reached from the entrance?
2758-
if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) {
2759-
AllReachable = false;
2760-
break;
2761-
}
2762-
}
2763-
// If we cannot map to a basic block, assume the statement is
2764-
// reachable.
2765-
}
2766-
2767-
if (AllReachable)
2741+
if (llvm::all_of(D.Stmts, [&](const Stmt *St) {
2742+
const CFGBlock *Block = AC.getBlockForRegisteredExpression(St);
2743+
CFGReverseBlockReachabilityAnalysis *Analysis =
2744+
AC.getCFGReachablityAnalysis();
2745+
if (Block && Analysis)
2746+
if (!Analysis->isReachable(&AC.getCFG()->getEntry(), Block))
2747+
return false;
2748+
return true;
2749+
})) {
27682750
S.Diag(D.Loc, D.PD);
2751+
}
27692752
}
2753+
} else {
2754+
for (const auto &D : PUDs)
2755+
S.Diag(D.Loc, D.PD);
27702756
}
2771-
2772-
if (!Analyzed)
2773-
FlushDiagnostics(PUDs);
27742757
}
27752758

27762759
void sema::AnalysisBasedWarnings::RegisterVarDeclWarning(
@@ -2780,12 +2763,10 @@ void sema::AnalysisBasedWarnings::RegisterVarDeclWarning(
27802763

27812764
void sema::AnalysisBasedWarnings::IssueWarningsForRegisteredVarDecl(
27822765
VarDecl *VD) {
2783-
if (VarDeclPossiblyUnreachableDiags.find(VD) ==
2784-
VarDeclPossiblyUnreachableDiags.end()) {
2766+
if (!llvm::is_contained(VarDeclPossiblyUnreachableDiags, VD))
27852767
return;
2786-
}
27872768

2788-
AnalysisDeclContext AC(nullptr, VD);
2769+
AnalysisDeclContext AC(/*Mgr=*/nullptr, VD);
27892770

27902771
AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;
27912772
AC.getCFGBuildOptions().AddEHEdges = false;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13103,9 +13103,9 @@ namespace {
1310313103
// Skip checking for file-scope constexpr variables - constant evaluation
1310413104
// will produce appropriate errors without needing runtime diagnostics.
1310513105
// Local constexpr should still emit runtime warnings.
13106-
if (auto *VD = dyn_cast<VarDecl>(OrigDecl))
13107-
if (VD->isConstexpr() && VD->isFileVarDecl())
13108-
return;
13106+
if (auto *VD = dyn_cast<VarDecl>(OrigDecl);
13107+
VD && VD->isConstexpr() && VD->isFileVarDecl())
13108+
return;
1310913109

1311013110
E = E->IgnoreParens();
1311113111

clang/test/Sema/warn-unreachable-file-scope.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ void f(void) {
2828
unsigned long long e3 = 1 ? 0 : 1ULL << 64;
2929
unsigned long long e4 = 0 ? 0 : 1ULL << 64; // expected-warning {{shift count >= width of type}}
3030
}
31+
32+
void statics(void) {
33+
static u8 f1 = (0 ? 0xffff : 0xff);
34+
static u8 f2 = (1 ? 0xffff : 0xff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
35+
static u8 f3 = (1 ? 0xff : 0xffff);
36+
static u8 f4 = (0 ? 0xff : 0xffff); // expected-warning {{implicit conversion from 'int' to 'u8' (aka 'unsigned char') changes value from 65535 to 255}}
37+
}

0 commit comments

Comments
 (0)