[clang] [clang][Wunsafe-buffer-usage] Add -Wunsafe-buffer-usage-in-static-sized-array (PR #176466)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 16 12:54:10 PST 2026
https://github.com/mxms0 updated https://github.com/llvm/llvm-project/pull/176466
>From 19944e88d79b1b8ebcc0bf343f251b52d8cc1868 Mon Sep 17 00:00:00 2001
From: mxms <mxms at google.com>
Date: Fri, 16 Jan 2026 19:33:44 +0000
Subject: [PATCH 1/5] [clang][-Wunsafe-buffer-usage] Add flag support for
-Wunsafe-buffer-usage-in-static-sized-arrays
---
.../Analysis/Analyses/UnsafeBufferUsage.h | 5 +
.../Analyses/UnsafeBufferUsageGadgets.def | 2 +-
clang/include/clang/Basic/DiagnosticGroups.td | 3 +-
.../clang/Basic/DiagnosticSemaKinds.td | 2 +
clang/lib/Analysis/UnsafeBufferUsage.cpp | 19 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 621 +++++++++---------
6 files changed, 334 insertions(+), 318 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index ea41eb3becfcf..462dabcc41da7 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -178,6 +178,11 @@ class UnsafeBufferUsageHandler {
virtual bool
ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const = 0;
+ /// \return true iff array subscript accesses on fixed size arrays should NOT
+ /// be reported at `Loc`
+ virtual bool
+ ignoreUnsafeBufferInStaticSizedArray(const SourceLocation &Loc) const = 0;
+
virtual std::string
getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
StringRef WSSuffix = "") const = 0;
diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index f9bba5d54e9c7..129ce95c1c0e0 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -33,12 +33,12 @@
WARNING_GADGET(Increment)
WARNING_GADGET(Decrement)
-WARNING_GADGET(ArraySubscript)
WARNING_GADGET(PointerArithmetic)
WARNING_GADGET(UnsafeBufferUsageAttr)
WARNING_GADGET(UnsafeBufferUsageCtorAttr)
WARNING_GADGET(DataInvocation)
WARNING_GADGET(UniquePtrArrayAccess)
+WARNING_OPTIONAL_GADGET(ArraySubscript)
WARNING_OPTIONAL_GADGET(UnsafeLibcFunctionCall)
WARNING_OPTIONAL_GADGET(UnsafeFormatAttributedFunctionCall)
WARNING_OPTIONAL_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 3764475fbd3df..f4717505e1bdd 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1774,7 +1774,8 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;
def UnsafeBufferUsageInContainer : DiagGroup<"unsafe-buffer-usage-in-container">;
def UnsafeBufferUsageInLibcCall : DiagGroup<"unsafe-buffer-usage-in-libc-call">;
def UnsafeBufferUsageInUniquePtrArrayAccess : DiagGroup<"unsafe-buffer-usage-in-unique-ptr-array-access">;
-def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, UnsafeBufferUsageInUniquePtrArrayAccess]>;
+def UnsafeBufferUsageInStaticSizedArray : DiagGroup<"unsafe-buffer-usage-in-static-sized-array">;
+def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, UnsafeBufferUsageInUniquePtrArrayAccess, UnsafeBufferUsageInStaticSizedArray]>;
// Warnings and notes InstallAPI verification.
def InstallAPIViolation : DiagGroup<"installapi-violation">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index eb7a608f798b8..1ab3f537d36a3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13472,6 +13472,8 @@ def warn_unsafe_buffer_usage_in_container : Warning<
InGroup<UnsafeBufferUsageInContainer>, DefaultIgnore;
def warn_unsafe_buffer_usage_unique_ptr_array_access : Warning<"direct access using operator[] on std::unique_ptr<T[]> is unsafe due to lack of bounds checking">,
InGroup<UnsafeBufferUsageInUniquePtrArrayAccess>, DefaultIgnore;
+def warn_unsafe_buffer_usage_in_static_sized_array : Warning<"direct access on T[N] is unsafe due to the lack of bounds checking">,
+ InGroup<UnsafeBufferUsageInStaticSizedArray>, DefaultIgnore;
#ifndef NDEBUG
// Not a user-facing diagnostic. Useful for debugging false negatives in
// -fsafe-buffer-usage-suggestions (i.e. lack of -Wunsafe-buffer-usage fixits).
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 6bb08102c0345..d7df7d8d46b61 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -667,7 +667,8 @@ static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node,
}
static bool isSafeArraySubscript(const ArraySubscriptExpr &Node,
- const ASTContext &Ctx) {
+ const ASTContext &Ctx,
+ const bool IgnoreStaticSizedArrays) {
// FIXME: Proper solution:
// - refactor Sema::CheckArrayAccess
// - split safe/OOB/unknown decision logic from diagnostics emitting code
@@ -689,6 +690,12 @@ static bool isSafeArraySubscript(const ArraySubscriptExpr &Node,
return false;
}
+ if (IgnoreStaticSizedArrays) {
+ // If we made it here, it means a size was found for the var being
+ // accessed. If it's fixed size, we can ignore it.
+ return true;
+ }
+
Expr::EvalResult EVResult;
const Expr *IndexExpr = Node.getIdx();
if (!IndexExpr->isValueDependent() &&
@@ -1568,6 +1575,7 @@ class ArraySubscriptGadget : public WarningGadget {
}
static bool matches(const Stmt *S, const ASTContext &Ctx,
+ const UnsafeBufferUsageHandler *Handler,
MatchResult &Result) {
const auto *ASE = dyn_cast<ArraySubscriptExpr>(S);
if (!ASE)
@@ -1578,7 +1586,10 @@ class ArraySubscriptGadget : public WarningGadget {
const auto *Idx = dyn_cast<IntegerLiteral>(ASE->getIdx());
bool IsSafeIndex = (Idx && Idx->getValue().isZero()) ||
isa<ArrayInitIndexExpr>(ASE->getIdx());
- if (IsSafeIndex || isSafeArraySubscript(*ASE, Ctx))
+ if (IsSafeIndex ||
+ isSafeArraySubscript(
+ *ASE, Ctx,
+ Handler->ignoreUnsafeBufferInStaticSizedArray(S->getBeginLoc())))
return false;
Result.addNode(ArraySubscrTag, DynTypedNode::create(*ASE));
return true;
@@ -2888,6 +2899,10 @@ std::set<const Expr *> clang::findUnsafePointers(const FunctionDecl *FD) {
bool ignoreUnsafeBufferInLibcCall(const SourceLocation &) const override {
return false;
}
+ bool ignoreUnsafeBufferInStaticSizedArray(
+ const SourceLocation &Loc) const override {
+ return false;
+ }
std::string getUnsafeBufferUsageAttributeTextAt(
SourceLocation, StringRef WSSuffix = "") const override {
return "";
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 56d7db649afbe..437397d3126c2 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -67,61 +67,60 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class UnreachableCodeHandler : public reachable_code::Callback {
- Sema &S;
- SourceRange PreviousSilenceableCondVal;
-
- public:
- UnreachableCodeHandler(Sema &s) : S(s) {}
-
- void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L,
- SourceRange SilenceableCondVal, SourceRange R1,
- SourceRange R2, bool HasFallThroughAttr) override {
- // If the diagnosed code is `[[fallthrough]];` and
- // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never
- // be executed` warning to avoid generating diagnostic twice
- if (HasFallThroughAttr &&
- !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
- SourceLocation()))
- return;
+class UnreachableCodeHandler : public reachable_code::Callback {
+ Sema &S;
+ SourceRange PreviousSilenceableCondVal;
- // Avoid reporting multiple unreachable code diagnostics that are
- // triggered by the same conditional value.
- if (PreviousSilenceableCondVal.isValid() &&
- SilenceableCondVal.isValid() &&
- PreviousSilenceableCondVal == SilenceableCondVal)
- return;
- PreviousSilenceableCondVal = SilenceableCondVal;
+public:
+ UnreachableCodeHandler(Sema &s) : S(s) {}
+
+ void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L,
+ SourceRange SilenceableCondVal, SourceRange R1,
+ SourceRange R2, bool HasFallThroughAttr) override {
+ // If the diagnosed code is `[[fallthrough]];` and
+ // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never
+ // be executed` warning to avoid generating diagnostic twice
+ if (HasFallThroughAttr &&
+ !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
+ SourceLocation()))
+ return;
- unsigned diag = diag::warn_unreachable;
- switch (UK) {
- case reachable_code::UK_Break:
- diag = diag::warn_unreachable_break;
- break;
- case reachable_code::UK_Return:
- diag = diag::warn_unreachable_return;
- break;
- case reachable_code::UK_Loop_Increment:
- diag = diag::warn_unreachable_loop_increment;
- break;
- case reachable_code::UK_Other:
- break;
- }
+ // Avoid reporting multiple unreachable code diagnostics that are
+ // triggered by the same conditional value.
+ if (PreviousSilenceableCondVal.isValid() && SilenceableCondVal.isValid() &&
+ PreviousSilenceableCondVal == SilenceableCondVal)
+ return;
+ PreviousSilenceableCondVal = SilenceableCondVal;
+
+ unsigned diag = diag::warn_unreachable;
+ switch (UK) {
+ case reachable_code::UK_Break:
+ diag = diag::warn_unreachable_break;
+ break;
+ case reachable_code::UK_Return:
+ diag = diag::warn_unreachable_return;
+ break;
+ case reachable_code::UK_Loop_Increment:
+ diag = diag::warn_unreachable_loop_increment;
+ break;
+ case reachable_code::UK_Other:
+ break;
+ }
- S.Diag(L, diag) << R1 << R2;
+ S.Diag(L, diag) << R1 << R2;
- SourceLocation Open = SilenceableCondVal.getBegin();
- if (Open.isValid()) {
- SourceLocation Close = SilenceableCondVal.getEnd();
- Close = S.getLocForEndOfToken(Close);
- if (Close.isValid()) {
- S.Diag(Open, diag::note_unreachable_silence)
+ SourceLocation Open = SilenceableCondVal.getBegin();
+ if (Open.isValid()) {
+ SourceLocation Close = SilenceableCondVal.getEnd();
+ Close = S.getLocForEndOfToken(Close);
+ if (Close.isValid()) {
+ S.Diag(Open, diag::note_unreachable_silence)
<< FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (")
<< FixItHint::CreateInsertion(Close, ")");
- }
}
}
- };
+ }
+};
} // anonymous namespace
/// CheckUnreachable - Check for unreachable code.
@@ -291,7 +290,8 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
return;
CFG *cfg = AC.getCFG();
- if (!cfg) return;
+ if (!cfg)
+ return;
// If the exit block is unreachable, skip processing the function.
if (cfg->getExit().pred_empty())
@@ -326,10 +326,9 @@ static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock,
if (Succ->getBlockID() == Body->getExit().getBlockID())
return true;
- if (auto *Catch =
- dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
+ if (auto *Catch = dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
QualType Caught = Catch->getCaughtType();
- if (Caught.isNull() || // catch (...) catches everything
+ if (Caught.isNull() || // catch (...) catches everything
!E->getSubExpr() || // throw; is considered cuaght by any handler
S.handlerCanCatch(Caught, E->getSubExpr()->getType()))
// Exception doesn't escape via this path.
@@ -348,7 +347,8 @@ static void visitReachableThrows(
CFG *BodyCFG,
llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) {
llvm::BitVector Reachable(BodyCFG->getNumBlockIDs());
- clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable);
+ clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(),
+ Reachable);
for (CFGBlock *B : *BodyCFG) {
if (!Reachable[B->getBlockID()])
continue;
@@ -371,8 +371,8 @@ static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,
(isa<CXXDestructorDecl>(FD) ||
FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||
FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) {
- if (const auto *Ty = FD->getTypeSourceInfo()->getType()->
- getAs<FunctionProtoType>())
+ if (const auto *Ty =
+ FD->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>())
S.Diag(FD->getLocation(), diag::note_throw_in_dtor)
<< !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
<< FD->getExceptionSpecSourceRange();
@@ -389,10 +389,11 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
return;
if (BodyCFG->getExit().pred_empty())
return;
- visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) {
- if (throwEscapes(S, Throw, Block, BodyCFG))
- EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD);
- });
+ visitReachableThrows(
+ BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) {
+ if (throwEscapes(S, Throw, Block, BodyCFG))
+ EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD);
+ });
}
static bool isNoexcept(const FunctionDecl *FD) {
@@ -565,13 +566,14 @@ enum ControlFlowKind {
/// will return.
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
CFG *cfg = AC.getCFG();
- if (!cfg) return UnknownFallThrough;
+ if (!cfg)
+ return UnknownFallThrough;
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
llvm::BitVector live(cfg->getNumBlockIDs());
- unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(),
- live);
+ unsigned count =
+ reachable_code::ScanReachableFromBlock(&cfg->getEntry(), live);
bool AddEHEdges = AC.getAddEHEdges();
if (!AddEHEdges && count != cfg->getNumBlockIDs())
@@ -624,7 +626,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
// statement (if it exists).
CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
- for ( ; ri != re ; ++ri)
+ for (; ri != re; ++ri)
if (ri->getAs<CFGStmt>())
break;
@@ -798,14 +800,12 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
else
ReturnsVoid = FD->getReturnType()->isVoidType();
HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
- }
- else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
ReturnsVoid = MD->getReturnType()->isVoidType();
HasNoReturn = MD->hasAttr<NoReturnAttr>();
- }
- else if (isa<BlockDecl>(D)) {
+ } else if (isa<BlockDecl>(D)) {
if (const FunctionType *FT =
- BlockType->getPointeeType()->getAs<FunctionType>()) {
+ BlockType->getPointeeType()->getAs<FunctionType>()) {
if (FT->getReturnType()->isVoidType())
ReturnsVoid = true;
if (FT->getNoReturnAttr())
@@ -817,7 +817,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
- return;
+ return;
SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc();
// cpu_dispatch functions permit empty function bodies for ICC compatibility.
@@ -894,7 +894,7 @@ class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {
typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)
- : Inherited(Context), FoundReference(false), Needle(Needle) {}
+ : Inherited(Context), FoundReference(false), Needle(Needle) {}
void VisitExpr(const Expr *E) {
// Stop evaluating if we already have a reference.
@@ -917,8 +917,7 @@ class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {
static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
QualType VariableTy = VD->getType().getCanonicalType();
- if (VariableTy->isBlockPointerType() &&
- !VD->hasAttr<BlocksAttr>()) {
+ if (VariableTy->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) {
S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization)
<< VD->getDeclName()
<< FixItHint::CreateInsertion(VD->getLocation(), "__block ");
@@ -940,16 +939,16 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
if (Init.empty())
return false;
- S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
- << FixItHint::CreateInsertion(Loc, Init);
+ S.Diag(Loc, diag::note_var_fixit_add_initialization)
+ << VD->getDeclName() << FixItHint::CreateInsertion(Loc, Init);
return true;
}
/// Create a fixit to remove an if-like statement, on the assumption that its
/// condition is CondVal.
static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then,
- const Stmt *Else, bool CondVal,
- FixItHint &Fixit1, FixItHint &Fixit2) {
+ const Stmt *Else, bool CondVal, FixItHint &Fixit1,
+ FixItHint &Fixit2) {
if (CondVal) {
// If condition is always true, remove all but the 'then'.
Fixit1 = FixItHint::CreateRemoval(
@@ -1016,9 +1015,9 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
// For all binary terminators, branch 0 is taken if the condition is true,
// and branch 1 is taken if the condition is false.
int RemoveDiagKind = -1;
- const char *FixitStr =
- S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false")
- : (I->Output ? "1" : "0");
+ const char *FixitStr = S.getLangOpts().CPlusPlus
+ ? (I->Output ? "true" : "false")
+ : (I->Output ? "1" : "0");
FixItHint Fixit1, Fixit2;
switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {
@@ -1034,8 +1033,8 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
Str = "if";
Range = IS->getCond()->getSourceRange();
RemoveDiagKind = 0;
- CreateIfFixit(S, IS, IS->getThen(), IS->getElse(),
- I->Output, Fixit1, Fixit2);
+ CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), I->Output, Fixit1,
+ Fixit2);
break;
}
case Stmt::ConditionalOperatorClass: {
@@ -1044,8 +1043,8 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
Str = "?:";
Range = CO->getCond()->getSourceRange();
RemoveDiagKind = 0;
- CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(),
- I->Output, Fixit1, Fixit2);
+ CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), I->Output,
+ Fixit1, Fixit2);
break;
}
case Stmt::BinaryOperatorClass: {
@@ -1120,13 +1119,13 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
}
S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
- << VD->getDeclName() << IsCapturedByBlock << DiagKind
- << Str << I->Output << Range;
+ << VD->getDeclName() << IsCapturedByBlock << DiagKind << Str
+ << I->Output << Range;
S.Diag(User->getBeginLoc(), diag::note_uninit_var_use)
<< IsCapturedByBlock << User->getSourceRange();
if (RemoveDiagKind != -1)
S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond)
- << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
+ << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
Diagnosed = true;
}
@@ -1296,32 +1295,32 @@ class FallthroughMapper : public DynamicRecursiveASTVisitor {
// Don't care about other unreachable statements.
}
}
- // If there are no unreachable statements, this may be a special
- // case in CFG:
- // case X: {
- // A a; // A has a destructor.
- // break;
- // }
- // // <<<< This place is represented by a 'hanging' CFG block.
- // case Y:
- continue;
+ // If there are no unreachable statements, this may be a special
+ // case in CFG:
+ // case X: {
+ // A a; // A has a destructor.
+ // break;
+ // }
+ // // <<<< This place is represented by a 'hanging' CFG block.
+ // case Y:
+ continue;
}
- const Stmt *LastStmt = getLastStmt(*P);
- if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
- markFallthroughVisited(AS);
- ++AnnotatedCnt;
- continue; // Fallthrough annotation, good.
- }
+ const Stmt *LastStmt = getLastStmt(*P);
+ if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
+ markFallthroughVisited(AS);
+ ++AnnotatedCnt;
+ continue; // Fallthrough annotation, good.
+ }
- if (!LastStmt) { // This block contains no executable statements.
- // Traverse its predecessors.
- std::copy(P->pred_begin(), P->pred_end(),
- std::back_inserter(BlockQueue));
- continue;
- }
+ if (!LastStmt) { // This block contains no executable statements.
+ // Traverse its predecessors.
+ std::copy(P->pred_begin(), P->pred_end(),
+ std::back_inserter(BlockQueue));
+ continue;
+ }
- ++UnannotatedCnt;
+ ++UnannotatedCnt;
}
return !!UnannotatedCnt;
}
@@ -1337,64 +1336,63 @@ class FallthroughMapper : public DynamicRecursiveASTVisitor {
return true;
}
- // We don't want to traverse local type declarations. We analyze their
- // methods separately.
- bool TraverseDecl(Decl *D) override { return true; }
-
- // We analyze lambda bodies separately. Skip them here.
- bool TraverseLambdaExpr(LambdaExpr *LE) override {
- // Traverse the captures, but not the body.
- for (const auto C : zip(LE->captures(), LE->capture_inits()))
- TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
- return true;
- }
+ // We don't want to traverse local type declarations. We analyze their
+ // methods separately.
+ bool TraverseDecl(Decl *D) override { return true; }
- private:
+ // We analyze lambda bodies separately. Skip them here.
+ bool TraverseLambdaExpr(LambdaExpr *LE) override {
+ // Traverse the captures, but not the body.
+ for (const auto C : zip(LE->captures(), LE->capture_inits()))
+ TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
+ return true;
+ }
- static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
- if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
- if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
- return AS;
- }
- return nullptr;
+private:
+ static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
+ if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
+ if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
+ return AS;
}
+ return nullptr;
+ }
- static const Stmt *getLastStmt(const CFGBlock &B) {
- if (const Stmt *Term = B.getTerminatorStmt())
- return Term;
- for (const CFGElement &Elem : llvm::reverse(B))
- if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
- return CS->getStmt();
- // Workaround to detect a statement thrown out by CFGBuilder:
- // case X: {} case Y:
- // case X: ; case Y:
- if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))
- if (!isa<SwitchCase>(SW->getSubStmt()))
- return SW->getSubStmt();
+ static const Stmt *getLastStmt(const CFGBlock &B) {
+ if (const Stmt *Term = B.getTerminatorStmt())
+ return Term;
+ for (const CFGElement &Elem : llvm::reverse(B))
+ if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
+ return CS->getStmt();
+ // Workaround to detect a statement thrown out by CFGBuilder:
+ // case X: {} case Y:
+ // case X: ; case Y:
+ if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))
+ if (!isa<SwitchCase>(SW->getSubStmt()))
+ return SW->getSubStmt();
- return nullptr;
- }
+ return nullptr;
+ }
- bool FoundSwitchStatements;
- AttrStmts FallthroughStmts;
- Sema &S;
- llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
+ bool FoundSwitchStatements;
+ AttrStmts FallthroughStmts;
+ Sema &S;
+ llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
};
} // anonymous namespace
static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
SourceLocation Loc) {
- TokenValue FallthroughTokens[] = {
- tok::l_square, tok::l_square,
- PP.getIdentifierInfo("fallthrough"),
- tok::r_square, tok::r_square
- };
-
- TokenValue ClangFallthroughTokens[] = {
- tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
- tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
- tok::r_square, tok::r_square
- };
+ TokenValue FallthroughTokens[] = {tok::l_square, tok::l_square,
+ PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square};
+
+ TokenValue ClangFallthroughTokens[] = {tok::l_square,
+ tok::l_square,
+ PP.getIdentifierInfo("clang"),
+ tok::coloncolon,
+ PP.getIdentifierInfo("fallthrough"),
+ tok::r_square,
+ tok::r_square};
bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C23;
@@ -1509,13 +1507,12 @@ static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
static void diagnoseRepeatedUseOfWeak(Sema &S,
const sema::FunctionScopeInfo *CurFn,
- const Decl *D,
- const ParentMap &PM) {
+ const Decl *D, const ParentMap &PM) {
typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
- StmtUsesPair;
+ StmtUsesPair;
ASTContext &Ctx = S.getASTContext();
@@ -1529,7 +1526,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// Find the first read of the weak object.
WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
- for ( ; UI != UE; ++UI) {
+ for (; UI != UE; ++UI) {
if (UI->isUnsafe())
break;
}
@@ -1586,12 +1583,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
// FIXME: Should we use a common classification enum and the same set of
// possibilities all throughout Sema?
- enum {
- Function,
- Method,
- Block,
- Lambda
- } FunctionKind;
+ enum { Function, Method, Block, Lambda } FunctionKind;
if (isa<sema::BlockScopeInfo>(CurFn))
FunctionKind = Block;
@@ -1622,12 +1614,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// Classify the weak object being accessed for better warning text.
// This enum should stay in sync with the cases in
// warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
- enum {
- Variable,
- Property,
- ImplicitProperty,
- Ivar
- } ObjectKind;
+ enum { Variable, Property, ImplicitProperty, Ivar } ObjectKind;
const NamedDecl *KeyProp = Key.getProperty();
if (isa<VarDecl>(KeyProp))
@@ -1729,7 +1716,7 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
}
private:
- static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
+ static bool hasAlwaysUninitializedUse(const UsesVec *vec) {
return llvm::any_of(*vec, [](const UninitUse &U) {
return U.getKind() == UninitUse::Always ||
U.getKind() == UninitUse::AfterCall ||
@@ -1979,10 +1966,10 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
: getNotes();
}
- public:
+public:
ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
- : S(S), FunLocation(FL), FunEndLocation(FEL),
- CurrentFunction(nullptr), Verbose(false) {}
+ : S(S), FunLocation(FL), FunEndLocation(FEL), CurrentFunction(nullptr),
+ Verbose(false) {}
void setVerbose(bool b) { Verbose = b; }
@@ -2077,18 +2064,18 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
bool ReentrancyMismatch) override {
unsigned DiagID = 0;
switch (LEK) {
- case LEK_LockedSomePredecessors:
- DiagID = diag::warn_lock_some_predecessors;
- break;
- case LEK_LockedSomeLoopIterations:
- DiagID = diag::warn_expecting_lock_held_on_loop;
- break;
- case LEK_LockedAtEndOfFunction:
- DiagID = diag::warn_no_unlock;
- break;
- case LEK_NotLockedAtEndOfFunction:
- DiagID = diag::warn_expecting_locked;
- break;
+ case LEK_LockedSomePredecessors:
+ DiagID = diag::warn_lock_some_predecessors;
+ break;
+ case LEK_LockedSomeLoopIterations:
+ DiagID = diag::warn_expecting_lock_held_on_loop;
+ break;
+ case LEK_LockedAtEndOfFunction:
+ DiagID = diag::warn_no_unlock;
+ break;
+ case LEK_NotLockedAtEndOfFunction:
+ DiagID = diag::warn_expecting_locked;
+ break;
}
if (LocEndOfScope.isInvalid())
LocEndOfScope = FunEndLocation;
@@ -2134,7 +2121,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
break;
}
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D << getLockKindFromAccessKind(AK));
+ << D << getLockKindFromAccessKind(AK));
Warnings.emplace_back(std::move(Warning), getNotes());
}
@@ -2145,43 +2132,42 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
unsigned DiagID = 0;
if (PossibleMatch) {
switch (POK) {
- case POK_VarAccess:
- DiagID = diag::warn_variable_requires_lock_precise;
- break;
- case POK_VarDereference:
- DiagID = diag::warn_var_deref_requires_lock_precise;
- break;
- case POK_FunctionCall:
- DiagID = diag::warn_fun_requires_lock_precise;
- break;
- case POK_PassByRef:
- DiagID = diag::warn_guarded_pass_by_reference;
- break;
- case POK_PtPassByRef:
- DiagID = diag::warn_pt_guarded_pass_by_reference;
- break;
- case POK_ReturnByRef:
- DiagID = diag::warn_guarded_return_by_reference;
- break;
- case POK_PtReturnByRef:
- DiagID = diag::warn_pt_guarded_return_by_reference;
- break;
- case POK_PassPointer:
- DiagID = diag::warn_guarded_pass_pointer;
- break;
- case POK_PtPassPointer:
- DiagID = diag::warn_pt_guarded_pass_pointer;
- break;
- case POK_ReturnPointer:
- DiagID = diag::warn_guarded_return_pointer;
- break;
- case POK_PtReturnPointer:
- DiagID = diag::warn_pt_guarded_return_pointer;
- break;
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock_precise;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock_precise;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock_precise;
+ break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
+ case POK_ReturnByRef:
+ DiagID = diag::warn_guarded_return_by_reference;
+ break;
+ case POK_PtReturnByRef:
+ DiagID = diag::warn_pt_guarded_return_by_reference;
+ break;
+ case POK_PassPointer:
+ DiagID = diag::warn_guarded_pass_pointer;
+ break;
+ case POK_PtPassPointer:
+ DiagID = diag::warn_pt_guarded_pass_pointer;
+ break;
+ case POK_ReturnPointer:
+ DiagID = diag::warn_guarded_return_pointer;
+ break;
+ case POK_PtReturnPointer:
+ DiagID = diag::warn_pt_guarded_return_pointer;
+ break;
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
- << D
- << LockName << LK);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << Kind << D << LockName << LK);
PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
<< *PossibleMatch);
if (Verbose && POK == POK_VarAccess) {
@@ -2193,43 +2179,42 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Warnings.emplace_back(std::move(Warning), getNotes(Note));
} else {
switch (POK) {
- case POK_VarAccess:
- DiagID = diag::warn_variable_requires_lock;
- break;
- case POK_VarDereference:
- DiagID = diag::warn_var_deref_requires_lock;
- break;
- case POK_FunctionCall:
- DiagID = diag::warn_fun_requires_lock;
- break;
- case POK_PassByRef:
- DiagID = diag::warn_guarded_pass_by_reference;
- break;
- case POK_PtPassByRef:
- DiagID = diag::warn_pt_guarded_pass_by_reference;
- break;
- case POK_ReturnByRef:
- DiagID = diag::warn_guarded_return_by_reference;
- break;
- case POK_PtReturnByRef:
- DiagID = diag::warn_pt_guarded_return_by_reference;
- break;
- case POK_PassPointer:
- DiagID = diag::warn_guarded_pass_pointer;
- break;
- case POK_PtPassPointer:
- DiagID = diag::warn_pt_guarded_pass_pointer;
- break;
- case POK_ReturnPointer:
- DiagID = diag::warn_guarded_return_pointer;
- break;
- case POK_PtReturnPointer:
- DiagID = diag::warn_pt_guarded_return_pointer;
- break;
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock;
+ break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
+ case POK_ReturnByRef:
+ DiagID = diag::warn_guarded_return_by_reference;
+ break;
+ case POK_PtReturnByRef:
+ DiagID = diag::warn_pt_guarded_return_by_reference;
+ break;
+ case POK_PassPointer:
+ DiagID = diag::warn_guarded_pass_pointer;
+ break;
+ case POK_PtPassPointer:
+ DiagID = diag::warn_pt_guarded_pass_pointer;
+ break;
+ case POK_ReturnPointer:
+ DiagID = diag::warn_guarded_return_pointer;
+ break;
+ case POK_PtReturnPointer:
+ DiagID = diag::warn_pt_guarded_return_pointer;
+ break;
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
- << D
- << LockName << LK);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << Kind << D << LockName << LK);
if (Verbose && POK == POK_VarAccess) {
PartialDiagnosticAt Note(D->getLocation(),
S.PDiag(diag::note_guarded_by_declared_here));
@@ -2241,9 +2226,9 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_acquire_requires_negative_cap)
- << Kind << LockName << Neg);
+ PartialDiagnosticAt Warning(
+ Loc, S.PDiag(diag::warn_acquire_requires_negative_cap)
+ << Kind << LockName << Neg);
Warnings.emplace_back(std::move(Warning), getNotes());
}
@@ -2263,22 +2248,20 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_acquired_before)
+ << Kind << L1Name << L2Name);
Warnings.emplace_back(std::move(Warning), getNotes());
}
void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
+ PartialDiagnosticAt Warning(
+ Loc, S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
Warnings.emplace_back(std::move(Warning), getNotes());
}
- void enterFunction(const FunctionDecl* FD) override {
- CurrentFunction = FD;
- }
+ void enterFunction(const FunctionDecl *FD) override { CurrentFunction = FD; }
- void leaveFunction(const FunctionDecl* FD) override {
+ void leaveFunction(const FunctionDecl *FD) override {
CurrentFunction = nullptr;
}
};
@@ -2299,7 +2282,6 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
DiagList Warnings;
public:
-
ConsumedWarningsHandler(Sema &S) : S(S) {}
void emitDiagnostics() override {
@@ -2313,8 +2295,8 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnLoopStateMismatch(SourceLocation Loc,
StringRef VariableName) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<
- VariableName);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch)
+ << VariableName);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2324,9 +2306,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
StringRef ExpectedState,
StringRef ObservedState) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(
- diag::warn_param_return_typestate_mismatch) << VariableName <<
- ExpectedState << ObservedState);
+ PartialDiagnosticAt Warning(
+ Loc, S.PDiag(diag::warn_param_return_typestate_mismatch)
+ << VariableName << ExpectedState << ObservedState);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2334,16 +2316,18 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
StringRef ObservedState) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(
- diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_param_typestate_mismatch)
+ << ExpectedState << ObservedState);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
StringRef TypeName) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(
- diag::warn_return_typestate_for_unconsumable_type) << TypeName);
+ PartialDiagnosticAt Warning(
+ Loc, S.PDiag(diag::warn_return_typestate_for_unconsumable_type)
+ << TypeName);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2351,8 +2335,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
StringRef ObservedState) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(
- diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_return_typestate_mismatch)
+ << ExpectedState << ObservedState);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2360,8 +2345,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(
- diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_use_of_temp_in_invalid_state)
+ << MethodName << State);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2369,8 +2355,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
StringRef State, SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<
- MethodName << VariableName << State);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state)
+ << MethodName << VariableName
+ << State);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2386,7 +2373,7 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
namespace {
class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Sema &S;
- bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions?
+ bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions?
// Lists as a string the names of variables in `VarGroupForVD` except for `VD`
// itself:
@@ -2425,7 +2412,7 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
public:
UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)
- : S(S), SuggestSuggestions(SuggestSuggestions) {}
+ : S(S), SuggestSuggestions(SuggestSuggestions) {}
void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl,
ASTContext &Ctx) override {
@@ -2602,7 +2589,7 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
#ifndef NDEBUG
if (areDebugNotesRequested())
- for (const DebugNote &Note: DebugNotesByVar[Variable])
+ for (const DebugNote &Note : DebugNotesByVar[Variable])
S.Diag(Note.first, diag::note_safe_buffer_debug_mode) << Note.second;
#endif
}
@@ -2629,6 +2616,12 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
}
+ bool ignoreUnsafeBufferInStaticSizedArray(
+ const SourceLocation &Loc) const override {
+ return S.Diags.isIgnored(
+ diag::warn_unsafe_buffer_usage_in_static_sized_array, Loc);
+ }
+
// Returns the text representation of clang::unsafe_buffer_usage attribute.
// `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace
// characters.
@@ -2698,8 +2691,7 @@ sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
NumUninitAnalysisBlockVisits(0),
- MaxUninitAnalysisBlockVisitsPerFunction(0) {
-}
+ MaxUninitAnalysisBlockVisitsPerFunction(0) {}
// We need this here for unique_ptr with forward declared class.
sema::AnalysisBasedWarnings::~AnalysisBasedWarnings() = default;
@@ -2943,7 +2935,7 @@ LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU,
}
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
- TranslationUnitDecl *TU) {
+ TranslationUnitDecl *TU) {
if (!TU)
return; // This is unexpected, give up quietly.
@@ -2957,7 +2949,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// UnsafeBufferUsage analysis settings.
bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
- bool UnsafeBufferUsageShouldEmitSuggestions = // Should != Can.
+ bool UnsafeBufferUsageShouldEmitSuggestions = // Should != Can.
UnsafeBufferUsageCanEmitSuggestions &&
DiagOpts.ShowSafeBufferUsageSuggestions;
bool UnsafeBufferUsageShouldSuggestSuggestions =
@@ -3065,13 +3057,13 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
AC.getCFGBuildOptions().setAllAlwaysAdd();
} else {
AC.getCFGBuildOptions()
- .setAlwaysAdd(Stmt::BinaryOperatorClass)
- .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
- .setAlwaysAdd(Stmt::BlockExprClass)
- .setAlwaysAdd(Stmt::CStyleCastExprClass)
- .setAlwaysAdd(Stmt::DeclRefExprClass)
- .setAlwaysAdd(Stmt::ImplicitCastExprClass)
- .setAlwaysAdd(Stmt::UnaryOperatorClass);
+ .setAlwaysAdd(Stmt::BinaryOperatorClass)
+ .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
+ .setAlwaysAdd(Stmt::BlockExprClass)
+ .setAlwaysAdd(Stmt::CStyleCastExprClass)
+ .setAlwaysAdd(Stmt::DeclRefExprClass)
+ .setAlwaysAdd(Stmt::ImplicitCastExprClass)
+ .setAlwaysAdd(Stmt::UnaryOperatorClass);
}
if (EnableLifetimeSafetyAnalysis) {
AC.getCFGBuildOptions().AddLifetime = true;
@@ -3153,12 +3145,10 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
++NumUninitAnalysisFunctions;
NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
- MaxUninitAnalysisVariablesPerFunction =
- std::max(MaxUninitAnalysisVariablesPerFunction,
- stats.NumVariablesAnalyzed);
- MaxUninitAnalysisBlockVisitsPerFunction =
- std::max(MaxUninitAnalysisBlockVisitsPerFunction,
- stats.NumBlockVisits);
+ MaxUninitAnalysisVariablesPerFunction = std::max(
+ MaxUninitAnalysisVariablesPerFunction, stats.NumVariablesAnalyzed);
+ MaxUninitAnalysisBlockVisitsPerFunction = std::max(
+ MaxUninitAnalysisBlockVisitsPerFunction, stats.NumBlockVisits);
}
}
}
@@ -3196,7 +3186,6 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc()))
diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());
-
// Check for infinite self-recursion in functions
if (!Diags.isIgnored(diag::warn_infinite_recursive_function,
D->getBeginLoc())) {
@@ -3227,8 +3216,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// If we successfully built a CFG for this context, record some more
// detail information about it.
NumCFGBlocks += cfg->getNumBlockIDs();
- MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
- cfg->getNumBlockIDs());
+ MaxCFGBlocksPerFunction =
+ std::max(MaxCFGBlocksPerFunction, cfg->getNumBlockIDs());
} else {
++NumFunctionsWithBadCFGs;
}
@@ -3240,7 +3229,7 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const {
unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
unsigned AvgCFGBlocksPerFunction =
- !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
+ !NumCFGsBuilt ? 0 : NumCFGBlocks / NumCFGsBuilt;
llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
<< NumFunctionsWithBadCFGs << " w/o CFGs).\n"
<< " " << NumCFGBlocks << " CFG blocks built.\n"
@@ -3249,10 +3238,14 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const {
<< " " << MaxCFGBlocksPerFunction
<< " max CFG blocks per function.\n";
- unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
- : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
- unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
- : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
+ unsigned AvgUninitVariablesPerFunction =
+ !NumUninitAnalysisFunctions
+ ? 0
+ : NumUninitAnalysisVariables / NumUninitAnalysisFunctions;
+ unsigned AvgUninitBlockVisitsPerFunction =
+ !NumUninitAnalysisFunctions
+ ? 0
+ : NumUninitAnalysisBlockVisits / NumUninitAnalysisFunctions;
llvm::errs() << NumUninitAnalysisFunctions
<< " functions analyzed for uninitialiazed variables\n"
<< " " << NumUninitAnalysisVariables << " variables analyzed.\n"
>From 58f9857e0c70f3575884a6f7f3a92f46f51131ba Mon Sep 17 00:00:00 2001
From: mxms <mxms at google.com>
Date: Fri, 16 Jan 2026 19:33:44 +0000
Subject: [PATCH 2/5] [clang][-Wunsafe-buffer-usage] Add flag support for
-Wunsafe-buffer-usage-in-static-sized-arrays
---
...afe-buffer-usage-in-static-sized-array.cpp | 159 ++++++++++++++++++
1 file changed, 159 insertions(+)
create mode 100644 clang/test/SemaCXX/warn-unsafe-buffer-usage-in-static-sized-array.cpp
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-static-sized-array.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-static-sized-array.cpp
new file mode 100644
index 0000000000000..c4813198bbd9a
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-static-sized-array.cpp
@@ -0,0 +1,159 @@
+// RUN: %clang_cc1 -std=c++20 -Wno-everything -Wunsafe-buffer-usage \
+// RUN: -Wno-unsafe-buffer-usage-in-static-sized-array \
+// RUN: -fsafe-buffer-usage-suggestions \
+// RUN: -verify %s
+
+// CHECK-NOT: [-Wunsafe-buffer-usage]
+// expected-no-diagnostics
+
+void foo(unsigned idx) {
+ int buffer[10];
+ buffer[idx] = 0;
+}
+
+int global_buffer[10];
+void foo2(unsigned idx) { global_buffer[idx] = 0; }
+
+struct Foo {
+ int member_buffer[10];
+ int x;
+};
+
+void foo2(Foo &f, unsigned idx) { f.member_buffer[idx] = 0; }
+
+void constant_idx_safe(unsigned idx) {
+ int buffer[10];
+ buffer[9] = 0;
+}
+
+void constant_idx_safe0(unsigned idx) {
+ int buffer[10];
+ buffer[0] = 0;
+}
+
+int array[10];
+
+void circular_access_unsigned(unsigned idx) {
+ array[idx % 10];
+ array[idx % 11];
+ array[(idx + 3) % 10];
+ array[(--idx) % 8];
+ array[idx & 9 % 10];
+ array[9 & idx % 11];
+ array[12 % 10];
+}
+
+void circular_access_signed(int idx) { array[idx % 10]; }
+
+void masked_idx1(unsigned long long idx, Foo f) {
+ // Bitwise and operation
+ array[idx & 5] = 10;
+ array[5 & idx] = 12;
+ array[idx & 11 & 5] = 3;
+ array[idx & 11] = 20;
+ array[idx &= 5];
+ array[f.x & 5];
+ array[5 & f.x];
+ array[f.x & (-5)];
+}
+
+typedef unsigned long long uint64_t;
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+
+void type_conversions(uint64_t idx1, uint32_t idx2, uint8_t idx3) {
+ array[(uint32_t)idx1 & 3];
+ array[idx2 & 3];
+ array[idx3 & 3];
+}
+
+int array2[5];
+
+void masked_idx_safe(unsigned long long idx) {
+ array2[6 & 5];
+ array2[6 & idx & (idx + 1) & 5];
+}
+
+void constant_idx_unsafe(unsigned idx) {
+ int buffer[10];
+ buffer[10] = 0;
+}
+
+void constant_id_string(unsigned idx) {
+ char safe_char = "abc"[1];
+ safe_char = ""[0];
+ safe_char = "\0"[0];
+
+ char abcd[5] = "abc";
+ abcd[2];
+
+ char unsafe_char = "abc"[3];
+ unsafe_char = "abc"[-1];
+ unsafe_char = ""[1];
+ unsafe_char = ""[idx];
+}
+
+typedef float Float4x4[4][4];
+
+float two_dimension_array(Float4x4 &matrix, unsigned idx) {
+ float a = matrix[0][4];
+
+ a = matrix[0][3];
+
+ a = matrix[4][0];
+
+ a = matrix[idx][0];
+
+ a = matrix[0][idx];
+
+ a = matrix[idx][idx];
+
+ return matrix[1][1];
+}
+
+typedef float Float2x3x4[2][3][4];
+float multi_dimension_array(Float2x3x4 &matrix) {
+ float *f = matrix[0][2];
+ return matrix[1][2][3];
+}
+
+char array_strings[][11] = {"Apple", "Banana", "Cherry", "Date", "Elderberry"};
+
+char array_string[] = "123456";
+
+char access_strings() {
+ char c = array_strings[0][4];
+ c = array_strings[3][10];
+ c = array_string[5];
+ return c;
+}
+
+struct T {
+ int array[10];
+};
+
+const int index = 1;
+
+constexpr int get_const(int x) {
+ if (x < 3)
+ return ++x;
+ else
+ return x + 5;
+};
+
+void array_indexed_const_expr(unsigned idx) {
+ int arr[10];
+ arr[sizeof(int)] = 5;
+
+ int array[sizeof(T)];
+ array[sizeof(int)] = 5;
+ array[sizeof(T) - 1] = 3;
+
+ int k = arr[6 & 5];
+ k = arr[2 << index];
+ k = arr[8 << index];
+ k = arr[16 >> 1];
+ k = arr[get_const(index)];
+ k = arr[get_const(5)];
+ k = arr[get_const(4)];
+}
>From a0f4e48efe50af38c533701ea28ec59615d4d098 Mon Sep 17 00:00:00 2001
From: mxms <mxms at google.com>
Date: Fri, 16 Jan 2026 19:33:44 +0000
Subject: [PATCH 3/5] [clang][-Wunsafe-buffer-usage] Add flag support for
-Wunsafe-buffer-usage-in-static-sized-arrays
---
clang/lib/Sema/AnalysisBasedWarnings.cpp | 621 ++++++++++++-----------
1 file changed, 314 insertions(+), 307 deletions(-)
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 437397d3126c2..56d7db649afbe 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -67,60 +67,61 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
-class UnreachableCodeHandler : public reachable_code::Callback {
- Sema &S;
- SourceRange PreviousSilenceableCondVal;
-
-public:
- UnreachableCodeHandler(Sema &s) : S(s) {}
-
- void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L,
- SourceRange SilenceableCondVal, SourceRange R1,
- SourceRange R2, bool HasFallThroughAttr) override {
- // If the diagnosed code is `[[fallthrough]];` and
- // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never
- // be executed` warning to avoid generating diagnostic twice
- if (HasFallThroughAttr &&
- !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
- SourceLocation()))
- return;
+ class UnreachableCodeHandler : public reachable_code::Callback {
+ Sema &S;
+ SourceRange PreviousSilenceableCondVal;
+
+ public:
+ UnreachableCodeHandler(Sema &s) : S(s) {}
+
+ void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L,
+ SourceRange SilenceableCondVal, SourceRange R1,
+ SourceRange R2, bool HasFallThroughAttr) override {
+ // If the diagnosed code is `[[fallthrough]];` and
+ // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never
+ // be executed` warning to avoid generating diagnostic twice
+ if (HasFallThroughAttr &&
+ !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr,
+ SourceLocation()))
+ return;
- // Avoid reporting multiple unreachable code diagnostics that are
- // triggered by the same conditional value.
- if (PreviousSilenceableCondVal.isValid() && SilenceableCondVal.isValid() &&
- PreviousSilenceableCondVal == SilenceableCondVal)
- return;
- PreviousSilenceableCondVal = SilenceableCondVal;
+ // Avoid reporting multiple unreachable code diagnostics that are
+ // triggered by the same conditional value.
+ if (PreviousSilenceableCondVal.isValid() &&
+ SilenceableCondVal.isValid() &&
+ PreviousSilenceableCondVal == SilenceableCondVal)
+ return;
+ PreviousSilenceableCondVal = SilenceableCondVal;
- unsigned diag = diag::warn_unreachable;
- switch (UK) {
- case reachable_code::UK_Break:
- diag = diag::warn_unreachable_break;
- break;
- case reachable_code::UK_Return:
- diag = diag::warn_unreachable_return;
- break;
- case reachable_code::UK_Loop_Increment:
- diag = diag::warn_unreachable_loop_increment;
- break;
- case reachable_code::UK_Other:
- break;
- }
+ unsigned diag = diag::warn_unreachable;
+ switch (UK) {
+ case reachable_code::UK_Break:
+ diag = diag::warn_unreachable_break;
+ break;
+ case reachable_code::UK_Return:
+ diag = diag::warn_unreachable_return;
+ break;
+ case reachable_code::UK_Loop_Increment:
+ diag = diag::warn_unreachable_loop_increment;
+ break;
+ case reachable_code::UK_Other:
+ break;
+ }
- S.Diag(L, diag) << R1 << R2;
+ S.Diag(L, diag) << R1 << R2;
- SourceLocation Open = SilenceableCondVal.getBegin();
- if (Open.isValid()) {
- SourceLocation Close = SilenceableCondVal.getEnd();
- Close = S.getLocForEndOfToken(Close);
- if (Close.isValid()) {
- S.Diag(Open, diag::note_unreachable_silence)
+ SourceLocation Open = SilenceableCondVal.getBegin();
+ if (Open.isValid()) {
+ SourceLocation Close = SilenceableCondVal.getEnd();
+ Close = S.getLocForEndOfToken(Close);
+ if (Close.isValid()) {
+ S.Diag(Open, diag::note_unreachable_silence)
<< FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (")
<< FixItHint::CreateInsertion(Close, ")");
+ }
}
}
- }
-};
+ };
} // anonymous namespace
/// CheckUnreachable - Check for unreachable code.
@@ -290,8 +291,7 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
return;
CFG *cfg = AC.getCFG();
- if (!cfg)
- return;
+ if (!cfg) return;
// If the exit block is unreachable, skip processing the function.
if (cfg->getExit().pred_empty())
@@ -326,9 +326,10 @@ static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock,
if (Succ->getBlockID() == Body->getExit().getBlockID())
return true;
- if (auto *Catch = dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
+ if (auto *Catch =
+ dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
QualType Caught = Catch->getCaughtType();
- if (Caught.isNull() || // catch (...) catches everything
+ if (Caught.isNull() || // catch (...) catches everything
!E->getSubExpr() || // throw; is considered cuaght by any handler
S.handlerCanCatch(Caught, E->getSubExpr()->getType()))
// Exception doesn't escape via this path.
@@ -347,8 +348,7 @@ static void visitReachableThrows(
CFG *BodyCFG,
llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) {
llvm::BitVector Reachable(BodyCFG->getNumBlockIDs());
- clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(),
- Reachable);
+ clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable);
for (CFGBlock *B : *BodyCFG) {
if (!Reachable[B->getBlockID()])
continue;
@@ -371,8 +371,8 @@ static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,
(isa<CXXDestructorDecl>(FD) ||
FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||
FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) {
- if (const auto *Ty =
- FD->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>())
+ if (const auto *Ty = FD->getTypeSourceInfo()->getType()->
+ getAs<FunctionProtoType>())
S.Diag(FD->getLocation(), diag::note_throw_in_dtor)
<< !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
<< FD->getExceptionSpecSourceRange();
@@ -389,11 +389,10 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
return;
if (BodyCFG->getExit().pred_empty())
return;
- visitReachableThrows(
- BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) {
- if (throwEscapes(S, Throw, Block, BodyCFG))
- EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD);
- });
+ visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) {
+ if (throwEscapes(S, Throw, Block, BodyCFG))
+ EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD);
+ });
}
static bool isNoexcept(const FunctionDecl *FD) {
@@ -566,14 +565,13 @@ enum ControlFlowKind {
/// will return.
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
CFG *cfg = AC.getCFG();
- if (!cfg)
- return UnknownFallThrough;
+ if (!cfg) return UnknownFallThrough;
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
llvm::BitVector live(cfg->getNumBlockIDs());
- unsigned count =
- reachable_code::ScanReachableFromBlock(&cfg->getEntry(), live);
+ unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(),
+ live);
bool AddEHEdges = AC.getAddEHEdges();
if (!AddEHEdges && count != cfg->getNumBlockIDs())
@@ -626,7 +624,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
// statement (if it exists).
CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
- for (; ri != re; ++ri)
+ for ( ; ri != re ; ++ri)
if (ri->getAs<CFGStmt>())
break;
@@ -800,12 +798,14 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
else
ReturnsVoid = FD->getReturnType()->isVoidType();
HasNoReturn = FD->isNoReturn() || FD->hasAttr<InferredNoReturnAttr>();
- } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ }
+ else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
ReturnsVoid = MD->getReturnType()->isVoidType();
HasNoReturn = MD->hasAttr<NoReturnAttr>();
- } else if (isa<BlockDecl>(D)) {
+ }
+ else if (isa<BlockDecl>(D)) {
if (const FunctionType *FT =
- BlockType->getPointeeType()->getAs<FunctionType>()) {
+ BlockType->getPointeeType()->getAs<FunctionType>()) {
if (FT->getReturnType()->isVoidType())
ReturnsVoid = true;
if (FT->getNoReturnAttr())
@@ -817,7 +817,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
- return;
+ return;
SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc();
// cpu_dispatch functions permit empty function bodies for ICC compatibility.
@@ -894,7 +894,7 @@ class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {
typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)
- : Inherited(Context), FoundReference(false), Needle(Needle) {}
+ : Inherited(Context), FoundReference(false), Needle(Needle) {}
void VisitExpr(const Expr *E) {
// Stop evaluating if we already have a reference.
@@ -917,7 +917,8 @@ class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {
static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
QualType VariableTy = VD->getType().getCanonicalType();
- if (VariableTy->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) {
+ if (VariableTy->isBlockPointerType() &&
+ !VD->hasAttr<BlocksAttr>()) {
S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization)
<< VD->getDeclName()
<< FixItHint::CreateInsertion(VD->getLocation(), "__block ");
@@ -939,16 +940,16 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
if (Init.empty())
return false;
- S.Diag(Loc, diag::note_var_fixit_add_initialization)
- << VD->getDeclName() << FixItHint::CreateInsertion(Loc, Init);
+ S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
+ << FixItHint::CreateInsertion(Loc, Init);
return true;
}
/// Create a fixit to remove an if-like statement, on the assumption that its
/// condition is CondVal.
static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then,
- const Stmt *Else, bool CondVal, FixItHint &Fixit1,
- FixItHint &Fixit2) {
+ const Stmt *Else, bool CondVal,
+ FixItHint &Fixit1, FixItHint &Fixit2) {
if (CondVal) {
// If condition is always true, remove all but the 'then'.
Fixit1 = FixItHint::CreateRemoval(
@@ -1015,9 +1016,9 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
// For all binary terminators, branch 0 is taken if the condition is true,
// and branch 1 is taken if the condition is false.
int RemoveDiagKind = -1;
- const char *FixitStr = S.getLangOpts().CPlusPlus
- ? (I->Output ? "true" : "false")
- : (I->Output ? "1" : "0");
+ const char *FixitStr =
+ S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false")
+ : (I->Output ? "1" : "0");
FixItHint Fixit1, Fixit2;
switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {
@@ -1033,8 +1034,8 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
Str = "if";
Range = IS->getCond()->getSourceRange();
RemoveDiagKind = 0;
- CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), I->Output, Fixit1,
- Fixit2);
+ CreateIfFixit(S, IS, IS->getThen(), IS->getElse(),
+ I->Output, Fixit1, Fixit2);
break;
}
case Stmt::ConditionalOperatorClass: {
@@ -1043,8 +1044,8 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
Str = "?:";
Range = CO->getCond()->getSourceRange();
RemoveDiagKind = 0;
- CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), I->Output,
- Fixit1, Fixit2);
+ CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(),
+ I->Output, Fixit1, Fixit2);
break;
}
case Stmt::BinaryOperatorClass: {
@@ -1119,13 +1120,13 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
}
S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var)
- << VD->getDeclName() << IsCapturedByBlock << DiagKind << Str
- << I->Output << Range;
+ << VD->getDeclName() << IsCapturedByBlock << DiagKind
+ << Str << I->Output << Range;
S.Diag(User->getBeginLoc(), diag::note_uninit_var_use)
<< IsCapturedByBlock << User->getSourceRange();
if (RemoveDiagKind != -1)
S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond)
- << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
+ << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2;
Diagnosed = true;
}
@@ -1295,32 +1296,32 @@ class FallthroughMapper : public DynamicRecursiveASTVisitor {
// Don't care about other unreachable statements.
}
}
- // If there are no unreachable statements, this may be a special
- // case in CFG:
- // case X: {
- // A a; // A has a destructor.
- // break;
- // }
- // // <<<< This place is represented by a 'hanging' CFG block.
- // case Y:
- continue;
+ // If there are no unreachable statements, this may be a special
+ // case in CFG:
+ // case X: {
+ // A a; // A has a destructor.
+ // break;
+ // }
+ // // <<<< This place is represented by a 'hanging' CFG block.
+ // case Y:
+ continue;
}
- const Stmt *LastStmt = getLastStmt(*P);
- if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
- markFallthroughVisited(AS);
- ++AnnotatedCnt;
- continue; // Fallthrough annotation, good.
- }
+ const Stmt *LastStmt = getLastStmt(*P);
+ if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) {
+ markFallthroughVisited(AS);
+ ++AnnotatedCnt;
+ continue; // Fallthrough annotation, good.
+ }
- if (!LastStmt) { // This block contains no executable statements.
- // Traverse its predecessors.
- std::copy(P->pred_begin(), P->pred_end(),
- std::back_inserter(BlockQueue));
- continue;
- }
+ if (!LastStmt) { // This block contains no executable statements.
+ // Traverse its predecessors.
+ std::copy(P->pred_begin(), P->pred_end(),
+ std::back_inserter(BlockQueue));
+ continue;
+ }
- ++UnannotatedCnt;
+ ++UnannotatedCnt;
}
return !!UnannotatedCnt;
}
@@ -1336,63 +1337,64 @@ class FallthroughMapper : public DynamicRecursiveASTVisitor {
return true;
}
- // We don't want to traverse local type declarations. We analyze their
- // methods separately.
- bool TraverseDecl(Decl *D) override { return true; }
+ // We don't want to traverse local type declarations. We analyze their
+ // methods separately.
+ bool TraverseDecl(Decl *D) override { return true; }
- // We analyze lambda bodies separately. Skip them here.
- bool TraverseLambdaExpr(LambdaExpr *LE) override {
- // Traverse the captures, but not the body.
- for (const auto C : zip(LE->captures(), LE->capture_inits()))
- TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
- return true;
- }
+ // We analyze lambda bodies separately. Skip them here.
+ bool TraverseLambdaExpr(LambdaExpr *LE) override {
+ // Traverse the captures, but not the body.
+ for (const auto C : zip(LE->captures(), LE->capture_inits()))
+ TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
+ return true;
+ }
-private:
- static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
- if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
- if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
- return AS;
+ private:
+
+ static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
+ if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) {
+ if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
+ return AS;
+ }
+ return nullptr;
}
- return nullptr;
- }
- static const Stmt *getLastStmt(const CFGBlock &B) {
- if (const Stmt *Term = B.getTerminatorStmt())
- return Term;
- for (const CFGElement &Elem : llvm::reverse(B))
- if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
- return CS->getStmt();
- // Workaround to detect a statement thrown out by CFGBuilder:
- // case X: {} case Y:
- // case X: ; case Y:
- if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))
- if (!isa<SwitchCase>(SW->getSubStmt()))
- return SW->getSubStmt();
+ static const Stmt *getLastStmt(const CFGBlock &B) {
+ if (const Stmt *Term = B.getTerminatorStmt())
+ return Term;
+ for (const CFGElement &Elem : llvm::reverse(B))
+ if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
+ return CS->getStmt();
+ // Workaround to detect a statement thrown out by CFGBuilder:
+ // case X: {} case Y:
+ // case X: ; case Y:
+ if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel()))
+ if (!isa<SwitchCase>(SW->getSubStmt()))
+ return SW->getSubStmt();
- return nullptr;
- }
+ return nullptr;
+ }
- bool FoundSwitchStatements;
- AttrStmts FallthroughStmts;
- Sema &S;
- llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
+ bool FoundSwitchStatements;
+ AttrStmts FallthroughStmts;
+ Sema &S;
+ llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
};
} // anonymous namespace
static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
SourceLocation Loc) {
- TokenValue FallthroughTokens[] = {tok::l_square, tok::l_square,
- PP.getIdentifierInfo("fallthrough"),
- tok::r_square, tok::r_square};
-
- TokenValue ClangFallthroughTokens[] = {tok::l_square,
- tok::l_square,
- PP.getIdentifierInfo("clang"),
- tok::coloncolon,
- PP.getIdentifierInfo("fallthrough"),
- tok::r_square,
- tok::r_square};
+ TokenValue FallthroughTokens[] = {
+ tok::l_square, tok::l_square,
+ PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+
+ TokenValue ClangFallthroughTokens[] = {
+ tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
+ tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C23;
@@ -1507,12 +1509,13 @@ static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
static void diagnoseRepeatedUseOfWeak(Sema &S,
const sema::FunctionScopeInfo *CurFn,
- const Decl *D, const ParentMap &PM) {
+ const Decl *D,
+ const ParentMap &PM) {
typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
- StmtUsesPair;
+ StmtUsesPair;
ASTContext &Ctx = S.getASTContext();
@@ -1526,7 +1529,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// Find the first read of the weak object.
WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
- for (; UI != UE; ++UI) {
+ for ( ; UI != UE; ++UI) {
if (UI->isUnsafe())
break;
}
@@ -1583,7 +1586,12 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
// FIXME: Should we use a common classification enum and the same set of
// possibilities all throughout Sema?
- enum { Function, Method, Block, Lambda } FunctionKind;
+ enum {
+ Function,
+ Method,
+ Block,
+ Lambda
+ } FunctionKind;
if (isa<sema::BlockScopeInfo>(CurFn))
FunctionKind = Block;
@@ -1614,7 +1622,12 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// Classify the weak object being accessed for better warning text.
// This enum should stay in sync with the cases in
// warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
- enum { Variable, Property, ImplicitProperty, Ivar } ObjectKind;
+ enum {
+ Variable,
+ Property,
+ ImplicitProperty,
+ Ivar
+ } ObjectKind;
const NamedDecl *KeyProp = Key.getProperty();
if (isa<VarDecl>(KeyProp))
@@ -1716,7 +1729,7 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
}
private:
- static bool hasAlwaysUninitializedUse(const UsesVec *vec) {
+ static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
return llvm::any_of(*vec, [](const UninitUse &U) {
return U.getKind() == UninitUse::Always ||
U.getKind() == UninitUse::AfterCall ||
@@ -1966,10 +1979,10 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
: getNotes();
}
-public:
+ public:
ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
- : S(S), FunLocation(FL), FunEndLocation(FEL), CurrentFunction(nullptr),
- Verbose(false) {}
+ : S(S), FunLocation(FL), FunEndLocation(FEL),
+ CurrentFunction(nullptr), Verbose(false) {}
void setVerbose(bool b) { Verbose = b; }
@@ -2064,18 +2077,18 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
bool ReentrancyMismatch) override {
unsigned DiagID = 0;
switch (LEK) {
- case LEK_LockedSomePredecessors:
- DiagID = diag::warn_lock_some_predecessors;
- break;
- case LEK_LockedSomeLoopIterations:
- DiagID = diag::warn_expecting_lock_held_on_loop;
- break;
- case LEK_LockedAtEndOfFunction:
- DiagID = diag::warn_no_unlock;
- break;
- case LEK_NotLockedAtEndOfFunction:
- DiagID = diag::warn_expecting_locked;
- break;
+ case LEK_LockedSomePredecessors:
+ DiagID = diag::warn_lock_some_predecessors;
+ break;
+ case LEK_LockedSomeLoopIterations:
+ DiagID = diag::warn_expecting_lock_held_on_loop;
+ break;
+ case LEK_LockedAtEndOfFunction:
+ DiagID = diag::warn_no_unlock;
+ break;
+ case LEK_NotLockedAtEndOfFunction:
+ DiagID = diag::warn_expecting_locked;
+ break;
}
if (LocEndOfScope.isInvalid())
LocEndOfScope = FunEndLocation;
@@ -2121,7 +2134,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
break;
}
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D << getLockKindFromAccessKind(AK));
+ << D << getLockKindFromAccessKind(AK));
Warnings.emplace_back(std::move(Warning), getNotes());
}
@@ -2132,42 +2145,43 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
unsigned DiagID = 0;
if (PossibleMatch) {
switch (POK) {
- case POK_VarAccess:
- DiagID = diag::warn_variable_requires_lock_precise;
- break;
- case POK_VarDereference:
- DiagID = diag::warn_var_deref_requires_lock_precise;
- break;
- case POK_FunctionCall:
- DiagID = diag::warn_fun_requires_lock_precise;
- break;
- case POK_PassByRef:
- DiagID = diag::warn_guarded_pass_by_reference;
- break;
- case POK_PtPassByRef:
- DiagID = diag::warn_pt_guarded_pass_by_reference;
- break;
- case POK_ReturnByRef:
- DiagID = diag::warn_guarded_return_by_reference;
- break;
- case POK_PtReturnByRef:
- DiagID = diag::warn_pt_guarded_return_by_reference;
- break;
- case POK_PassPointer:
- DiagID = diag::warn_guarded_pass_pointer;
- break;
- case POK_PtPassPointer:
- DiagID = diag::warn_pt_guarded_pass_pointer;
- break;
- case POK_ReturnPointer:
- DiagID = diag::warn_guarded_return_pointer;
- break;
- case POK_PtReturnPointer:
- DiagID = diag::warn_pt_guarded_return_pointer;
- break;
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock_precise;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock_precise;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock_precise;
+ break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
+ case POK_ReturnByRef:
+ DiagID = diag::warn_guarded_return_by_reference;
+ break;
+ case POK_PtReturnByRef:
+ DiagID = diag::warn_pt_guarded_return_by_reference;
+ break;
+ case POK_PassPointer:
+ DiagID = diag::warn_guarded_pass_pointer;
+ break;
+ case POK_PtPassPointer:
+ DiagID = diag::warn_pt_guarded_pass_pointer;
+ break;
+ case POK_ReturnPointer:
+ DiagID = diag::warn_guarded_return_pointer;
+ break;
+ case POK_PtReturnPointer:
+ DiagID = diag::warn_pt_guarded_return_pointer;
+ break;
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << Kind << D << LockName << LK);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
+ << D
+ << LockName << LK);
PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
<< *PossibleMatch);
if (Verbose && POK == POK_VarAccess) {
@@ -2179,42 +2193,43 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Warnings.emplace_back(std::move(Warning), getNotes(Note));
} else {
switch (POK) {
- case POK_VarAccess:
- DiagID = diag::warn_variable_requires_lock;
- break;
- case POK_VarDereference:
- DiagID = diag::warn_var_deref_requires_lock;
- break;
- case POK_FunctionCall:
- DiagID = diag::warn_fun_requires_lock;
- break;
- case POK_PassByRef:
- DiagID = diag::warn_guarded_pass_by_reference;
- break;
- case POK_PtPassByRef:
- DiagID = diag::warn_pt_guarded_pass_by_reference;
- break;
- case POK_ReturnByRef:
- DiagID = diag::warn_guarded_return_by_reference;
- break;
- case POK_PtReturnByRef:
- DiagID = diag::warn_pt_guarded_return_by_reference;
- break;
- case POK_PassPointer:
- DiagID = diag::warn_guarded_pass_pointer;
- break;
- case POK_PtPassPointer:
- DiagID = diag::warn_pt_guarded_pass_pointer;
- break;
- case POK_ReturnPointer:
- DiagID = diag::warn_guarded_return_pointer;
- break;
- case POK_PtReturnPointer:
- DiagID = diag::warn_pt_guarded_return_pointer;
- break;
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock;
+ break;
+ case POK_PassByRef:
+ DiagID = diag::warn_guarded_pass_by_reference;
+ break;
+ case POK_PtPassByRef:
+ DiagID = diag::warn_pt_guarded_pass_by_reference;
+ break;
+ case POK_ReturnByRef:
+ DiagID = diag::warn_guarded_return_by_reference;
+ break;
+ case POK_PtReturnByRef:
+ DiagID = diag::warn_pt_guarded_return_by_reference;
+ break;
+ case POK_PassPointer:
+ DiagID = diag::warn_guarded_pass_pointer;
+ break;
+ case POK_PtPassPointer:
+ DiagID = diag::warn_pt_guarded_pass_pointer;
+ break;
+ case POK_ReturnPointer:
+ DiagID = diag::warn_guarded_return_pointer;
+ break;
+ case POK_PtReturnPointer:
+ DiagID = diag::warn_pt_guarded_return_pointer;
+ break;
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << Kind << D << LockName << LK);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
+ << D
+ << LockName << LK);
if (Verbose && POK == POK_VarAccess) {
PartialDiagnosticAt Note(D->getLocation(),
S.PDiag(diag::note_guarded_by_declared_here));
@@ -2226,9 +2241,9 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
SourceLocation Loc) override {
- PartialDiagnosticAt Warning(
- Loc, S.PDiag(diag::warn_acquire_requires_negative_cap)
- << Kind << LockName << Neg);
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_acquire_requires_negative_cap)
+ << Kind << LockName << Neg);
Warnings.emplace_back(std::move(Warning), getNotes());
}
@@ -2248,20 +2263,22 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name,
SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_acquired_before)
- << Kind << L1Name << L2Name);
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
Warnings.emplace_back(std::move(Warning), getNotes());
}
void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override {
- PartialDiagnosticAt Warning(
- Loc, S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
Warnings.emplace_back(std::move(Warning), getNotes());
}
- void enterFunction(const FunctionDecl *FD) override { CurrentFunction = FD; }
+ void enterFunction(const FunctionDecl* FD) override {
+ CurrentFunction = FD;
+ }
- void leaveFunction(const FunctionDecl *FD) override {
+ void leaveFunction(const FunctionDecl* FD) override {
CurrentFunction = nullptr;
}
};
@@ -2282,6 +2299,7 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
DiagList Warnings;
public:
+
ConsumedWarningsHandler(Sema &S) : S(S) {}
void emitDiagnostics() override {
@@ -2295,8 +2313,8 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnLoopStateMismatch(SourceLocation Loc,
StringRef VariableName) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch)
- << VariableName);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<
+ VariableName);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2306,9 +2324,9 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
StringRef ExpectedState,
StringRef ObservedState) override {
- PartialDiagnosticAt Warning(
- Loc, S.PDiag(diag::warn_param_return_typestate_mismatch)
- << VariableName << ExpectedState << ObservedState);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_param_return_typestate_mismatch) << VariableName <<
+ ExpectedState << ObservedState);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2316,18 +2334,16 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
StringRef ObservedState) override {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_param_typestate_mismatch)
- << ExpectedState << ObservedState);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
StringRef TypeName) override {
- PartialDiagnosticAt Warning(
- Loc, S.PDiag(diag::warn_return_typestate_for_unconsumable_type)
- << TypeName);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_return_typestate_for_unconsumable_type) << TypeName);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2335,9 +2351,8 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
StringRef ObservedState) override {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_return_typestate_mismatch)
- << ExpectedState << ObservedState);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2345,9 +2360,8 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_use_of_temp_in_invalid_state)
- << MethodName << State);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2355,9 +2369,8 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
StringRef State, SourceLocation Loc) override {
- PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state)
- << MethodName << VariableName
- << State);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<
+ MethodName << VariableName << State);
Warnings.emplace_back(std::move(Warning), OptionalNotes());
}
@@ -2373,7 +2386,7 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
namespace {
class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Sema &S;
- bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions?
+ bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions?
// Lists as a string the names of variables in `VarGroupForVD` except for `VD`
// itself:
@@ -2412,7 +2425,7 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
public:
UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)
- : S(S), SuggestSuggestions(SuggestSuggestions) {}
+ : S(S), SuggestSuggestions(SuggestSuggestions) {}
void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl,
ASTContext &Ctx) override {
@@ -2589,7 +2602,7 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
#ifndef NDEBUG
if (areDebugNotesRequested())
- for (const DebugNote &Note : DebugNotesByVar[Variable])
+ for (const DebugNote &Note: DebugNotesByVar[Variable])
S.Diag(Note.first, diag::note_safe_buffer_debug_mode) << Note.second;
#endif
}
@@ -2616,12 +2629,6 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
}
- bool ignoreUnsafeBufferInStaticSizedArray(
- const SourceLocation &Loc) const override {
- return S.Diags.isIgnored(
- diag::warn_unsafe_buffer_usage_in_static_sized_array, Loc);
- }
-
// Returns the text representation of clang::unsafe_buffer_usage attribute.
// `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace
// characters.
@@ -2691,7 +2698,8 @@ sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
MaxCFGBlocksPerFunction(0), NumUninitAnalysisFunctions(0),
NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
NumUninitAnalysisBlockVisits(0),
- MaxUninitAnalysisBlockVisitsPerFunction(0) {}
+ MaxUninitAnalysisBlockVisitsPerFunction(0) {
+}
// We need this here for unique_ptr with forward declared class.
sema::AnalysisBasedWarnings::~AnalysisBasedWarnings() = default;
@@ -2935,7 +2943,7 @@ LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU,
}
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
- TranslationUnitDecl *TU) {
+ TranslationUnitDecl *TU) {
if (!TU)
return; // This is unexpected, give up quietly.
@@ -2949,7 +2957,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// UnsafeBufferUsage analysis settings.
bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20;
- bool UnsafeBufferUsageShouldEmitSuggestions = // Should != Can.
+ bool UnsafeBufferUsageShouldEmitSuggestions = // Should != Can.
UnsafeBufferUsageCanEmitSuggestions &&
DiagOpts.ShowSafeBufferUsageSuggestions;
bool UnsafeBufferUsageShouldSuggestSuggestions =
@@ -3057,13 +3065,13 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
AC.getCFGBuildOptions().setAllAlwaysAdd();
} else {
AC.getCFGBuildOptions()
- .setAlwaysAdd(Stmt::BinaryOperatorClass)
- .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
- .setAlwaysAdd(Stmt::BlockExprClass)
- .setAlwaysAdd(Stmt::CStyleCastExprClass)
- .setAlwaysAdd(Stmt::DeclRefExprClass)
- .setAlwaysAdd(Stmt::ImplicitCastExprClass)
- .setAlwaysAdd(Stmt::UnaryOperatorClass);
+ .setAlwaysAdd(Stmt::BinaryOperatorClass)
+ .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
+ .setAlwaysAdd(Stmt::BlockExprClass)
+ .setAlwaysAdd(Stmt::CStyleCastExprClass)
+ .setAlwaysAdd(Stmt::DeclRefExprClass)
+ .setAlwaysAdd(Stmt::ImplicitCastExprClass)
+ .setAlwaysAdd(Stmt::UnaryOperatorClass);
}
if (EnableLifetimeSafetyAnalysis) {
AC.getCFGBuildOptions().AddLifetime = true;
@@ -3145,10 +3153,12 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
++NumUninitAnalysisFunctions;
NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
- MaxUninitAnalysisVariablesPerFunction = std::max(
- MaxUninitAnalysisVariablesPerFunction, stats.NumVariablesAnalyzed);
- MaxUninitAnalysisBlockVisitsPerFunction = std::max(
- MaxUninitAnalysisBlockVisitsPerFunction, stats.NumBlockVisits);
+ MaxUninitAnalysisVariablesPerFunction =
+ std::max(MaxUninitAnalysisVariablesPerFunction,
+ stats.NumVariablesAnalyzed);
+ MaxUninitAnalysisBlockVisitsPerFunction =
+ std::max(MaxUninitAnalysisBlockVisitsPerFunction,
+ stats.NumBlockVisits);
}
}
}
@@ -3186,6 +3196,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc()))
diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());
+
// Check for infinite self-recursion in functions
if (!Diags.isIgnored(diag::warn_infinite_recursive_function,
D->getBeginLoc())) {
@@ -3216,8 +3227,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// If we successfully built a CFG for this context, record some more
// detail information about it.
NumCFGBlocks += cfg->getNumBlockIDs();
- MaxCFGBlocksPerFunction =
- std::max(MaxCFGBlocksPerFunction, cfg->getNumBlockIDs());
+ MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
+ cfg->getNumBlockIDs());
} else {
++NumFunctionsWithBadCFGs;
}
@@ -3229,7 +3240,7 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const {
unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
unsigned AvgCFGBlocksPerFunction =
- !NumCFGsBuilt ? 0 : NumCFGBlocks / NumCFGsBuilt;
+ !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
<< NumFunctionsWithBadCFGs << " w/o CFGs).\n"
<< " " << NumCFGBlocks << " CFG blocks built.\n"
@@ -3238,14 +3249,10 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const {
<< " " << MaxCFGBlocksPerFunction
<< " max CFG blocks per function.\n";
- unsigned AvgUninitVariablesPerFunction =
- !NumUninitAnalysisFunctions
- ? 0
- : NumUninitAnalysisVariables / NumUninitAnalysisFunctions;
- unsigned AvgUninitBlockVisitsPerFunction =
- !NumUninitAnalysisFunctions
- ? 0
- : NumUninitAnalysisBlockVisits / NumUninitAnalysisFunctions;
+ unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
+ : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
+ unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
+ : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
llvm::errs() << NumUninitAnalysisFunctions
<< " functions analyzed for uninitialiazed variables\n"
<< " " << NumUninitAnalysisVariables << " variables analyzed.\n"
>From be7d92a1f658efac9862cb26cd50f6cba57e7d08 Mon Sep 17 00:00:00 2001
From: mxms <mxms at google.com>
Date: Fri, 16 Jan 2026 19:44:31 +0000
Subject: [PATCH 4/5] Revert/fix
---
clang/lib/Sema/AnalysisBasedWarnings.cpp | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 56d7db649afbe..ab6fc49ef8233 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2629,6 +2629,12 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
return S.Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, Loc);
}
+ bool ignoreUnsafeBufferInStaticSizedArray(
+ const SourceLocation &Loc) const override {
+ return S.Diags.isIgnored(
+ diag::warn_unsafe_buffer_usage_in_static_sized_array, Loc);
+ }
+
// Returns the text representation of clang::unsafe_buffer_usage attribute.
// `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace
// characters.
>From 43e5a05b8a4a7493e8f6878b613d6b76cf9ec507 Mon Sep 17 00:00:00 2001
From: mxms <mxms at google.com>
Date: Fri, 16 Jan 2026 20:53:49 +0000
Subject: [PATCH 5/5] Updated comment
---
clang/lib/Analysis/UnsafeBufferUsage.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index d7df7d8d46b61..e0b2c9d4b9d9a 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -691,8 +691,8 @@ static bool isSafeArraySubscript(const ArraySubscriptExpr &Node,
}
if (IgnoreStaticSizedArrays) {
- // If we made it here, it means a size was found for the var being
- // accessed. If it's fixed size, we can ignore it.
+ // If we made it here, it means a size was found for the var being accessed
+ // (either string literal or array). If it's fixed size, we can ignore it.
return true;
}
More information about the cfe-commits
mailing list