[clang] [clang][SafeBuffers] Add -Wunsafe-buffer-usage-main-argv to allow ignoring main() argument warnings (PR #229871)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 8 13:48:30 PDT 2026
https://github.com/shreya-jain updated https://github.com/llvm/llvm-project/pull/229871
>From ffbb4a5a7659c63cd34f51410add1b74b1c92139 Mon Sep 17 00:00:00 2001
From: Shreya Jain <jainshreya at google.com>
Date: Mon, 5 Oct 2026 21:27:33 +0000
Subject: [PATCH 1/4] [clang][SafeBuffers] Add
-Wunsafe-buffer-usage-in-main-args sub-flag
---
clang/include/clang/Basic/DiagnosticGroups.td | 3 +-
.../clang/Basic/DiagnosticSemaKinds.td | 11 +++++++
clang/lib/Sema/AnalysisBasedWarnings.cpp | 31 +++++++++++++++++--
3 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 1da7698944b24b..b9f8d38ff39402 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1996,7 +1996,8 @@ def UnsafeBufferUsageInUniquePtrArrayAccess : DiagGroup<"unsafe-buffer-usage-in-
def UnsafeBufferUsageInStaticSizedArray : DiagGroup<"unsafe-buffer-usage-in-static-sized-array">;
def UnsafeBufferUsageInFormatAttrCall : DiagGroup<"unsafe-buffer-usage-in-format-attr-call">;
def UnsafeBufferUsageInStringView : DiagGroup<"unsafe-buffer-usage-in-string-view">;
-def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, UnsafeBufferUsageInUniquePtrArrayAccess, UnsafeBufferUsageInStaticSizedArray, UnsafeBufferUsageInFormatAttrCall, UnsafeBufferUsageInStringView]>;
+def UnsafeBufferUsageInMainArgs : DiagGroup<"unsafe-buffer-usage-in-main-args">;
+def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, UnsafeBufferUsageInUniquePtrArrayAccess, UnsafeBufferUsageInStaticSizedArray, UnsafeBufferUsageInFormatAttrCall, UnsafeBufferUsageInStringView, UnsafeBufferUsageInMainArgs]>;
// 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 9208aba1445d7e..35c24ef10e4642 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13914,10 +13914,21 @@ def err_cast_from_randomized_struct : Error<
"casting from randomized structure pointer type %0 to %1">;
// Unsafe buffer usage diagnostics.
+def warn_unsafe_buffer_variable_in_main_args : Warning<
+ "%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
+ "does not perform bounds checks}1">,
+ InGroup<UnsafeBufferUsageInMainArgs>, DefaultIgnore;
+
def warn_unsafe_buffer_variable : Warning<
"%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
"does not perform bounds checks}1">,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
+def warn_unsafe_buffer_usage_in_main_args : Warning<
+ "%select{unsafe pointer operation|unsafe pointer arithmetic|"
+ "unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
+ "field %1 prone to unsafe buffer manipulation}0">,
+ InGroup<UnsafeBufferUsageInMainArgs>, DefaultIgnore;
+
def warn_unsafe_buffer_operation : Warning<
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 99424c0e68b841..01332a2703def8 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2550,11 +2550,23 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
"Variables blamed for unsafe buffer usage without suggestions!");
S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
} else {
+ bool IsMainArg = false;
+ if (const auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext())) {
+ if (FD->isMain()) {
+ IsMainArg = true;
+ }
+ }
+ }
+
+ unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_usage_in_main_args
+ : diag::warn_unsafe_buffer_operation;
+
if (D) {
- S.Diag(Loc, diag::warn_unsafe_buffer_operation)
+ S.Diag(Loc, DiagID)
<< MsgParam << D << Range;
} else {
- S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;
+ S.Diag(Loc, DiagID) << MsgParam << Range;
}
if (SuggestSuggestions) {
S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
@@ -2640,7 +2652,20 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
const FixitStrategy &VarTargetTypes) override {
assert(!SuggestSuggestions &&
"Unsafe buffer usage fixits displayed without suggestions!");
- S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable)
+
+ bool IsMainArg = false;
+ if (const auto *PVD = dyn_cast<ParmVarDecl>(Variable)) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext())) {
+ if (FD->isMain()) {
+ IsMainArg = true;
+ }
+ }
+ }
+
+ unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_variable_in_main_args
+ : diag::warn_unsafe_buffer_variable;
+
+ S.Diag(Variable->getLocation(), DiagID)
<< Variable << (Variable->getType()->isPointerType() ? 0 : 1)
<< Variable->getSourceRange();
if (!Fixes.empty()) {
>From fa5ec2b835edacf4ac8580179978d6d83480c3a4 Mon Sep 17 00:00:00 2001
From: Shreya Jain <jainshreya at google.com>
Date: Mon, 5 Oct 2026 21:38:24 +0000
Subject: [PATCH 2/4] [clang][SafeBuffers] Extract array subscript base for
-Wunsafe-buffer-usage-main-argv
---
clang/include/clang/Basic/DiagnosticGroups.td | 4 +-
.../clang/Basic/DiagnosticSemaKinds.td | 8 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 640 +++++++++---------
.../warn-unsafe-buffer-usage-main-argv.cpp | 16 +
4 files changed, 343 insertions(+), 325 deletions(-)
create mode 100644 clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index b9f8d38ff39402..7779a6989cb7a9 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1996,8 +1996,8 @@ def UnsafeBufferUsageInUniquePtrArrayAccess : DiagGroup<"unsafe-buffer-usage-in-
def UnsafeBufferUsageInStaticSizedArray : DiagGroup<"unsafe-buffer-usage-in-static-sized-array">;
def UnsafeBufferUsageInFormatAttrCall : DiagGroup<"unsafe-buffer-usage-in-format-attr-call">;
def UnsafeBufferUsageInStringView : DiagGroup<"unsafe-buffer-usage-in-string-view">;
-def UnsafeBufferUsageInMainArgs : DiagGroup<"unsafe-buffer-usage-in-main-args">;
-def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, UnsafeBufferUsageInUniquePtrArrayAccess, UnsafeBufferUsageInStaticSizedArray, UnsafeBufferUsageInFormatAttrCall, UnsafeBufferUsageInStringView, UnsafeBufferUsageInMainArgs]>;
+def UnsafeBufferUsageMainArgv : DiagGroup<"unsafe-buffer-usage-main-argv">;
+def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer, UnsafeBufferUsageInLibcCall, UnsafeBufferUsageInUniquePtrArrayAccess, UnsafeBufferUsageInStaticSizedArray, UnsafeBufferUsageInFormatAttrCall, UnsafeBufferUsageInStringView, UnsafeBufferUsageMainArgv]>;
// 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 35c24ef10e4642..67ef836ec08180 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13914,20 +13914,20 @@ def err_cast_from_randomized_struct : Error<
"casting from randomized structure pointer type %0 to %1">;
// Unsafe buffer usage diagnostics.
-def warn_unsafe_buffer_variable_in_main_args : Warning<
+def warn_unsafe_buffer_variable_main_argv : Warning<
"%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
"does not perform bounds checks}1">,
- InGroup<UnsafeBufferUsageInMainArgs>, DefaultIgnore;
+ InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
def warn_unsafe_buffer_variable : Warning<
"%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
"does not perform bounds checks}1">,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
-def warn_unsafe_buffer_usage_in_main_args : Warning<
+def warn_unsafe_buffer_usage_main_argv : Warning<
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
"field %1 prone to unsafe buffer manipulation}0">,
- InGroup<UnsafeBufferUsageInMainArgs>, DefaultIgnore;
+ InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
def warn_unsafe_buffer_operation : Warning<
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 01332a2703def8..05fae91163bb24 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -71,61 +71,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;
- S.Diag(L, diag) << R1 << R2;
+ 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;
+ }
- 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)
+ 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)
<< FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (")
<< FixItHint::CreateInsertion(Close, ")");
- }
}
}
- };
+ }
+};
} // anonymous namespace
/// CheckUnreachable - Check for unreachable code.
@@ -295,7 +294,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())
@@ -330,10 +330,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.
@@ -352,7 +351,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;
@@ -375,8 +375,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();
@@ -393,10 +393,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) {
@@ -569,7 +570,8 @@ 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.
@@ -628,7 +630,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;
@@ -802,14 +804,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())
@@ -821,7 +821,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.
@@ -898,7 +898,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.
@@ -921,8 +921,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 ");
@@ -944,16 +943,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(
@@ -1020,9 +1019,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) {
@@ -1038,8 +1037,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: {
@@ -1048,8 +1047,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: {
@@ -1124,13 +1123,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;
}
@@ -1300,32 +1299,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;
}
@@ -1341,64 +1340,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 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;
- }
-
- 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;
@@ -1513,13 +1511,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();
@@ -1533,7 +1530,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;
}
@@ -1590,12 +1587,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;
@@ -1626,12 +1618,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))
@@ -1733,7 +1720,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 ||
@@ -1983,10 +1970,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; }
@@ -2081,18 +2068,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;
@@ -2138,7 +2125,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());
}
@@ -2182,43 +2169,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) {
@@ -2230,43 +2216,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));
@@ -2278,9 +2263,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());
}
@@ -2300,22 +2285,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;
}
};
@@ -2336,7 +2319,6 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
DiagList Warnings;
public:
-
ConsumedWarningsHandler(Sema &S) : S(S) {}
void emitDiagnostics() override {
@@ -2350,8 +2332,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());
}
@@ -2361,9 +2343,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());
}
@@ -2371,16 +2353,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());
}
@@ -2388,8 +2372,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());
}
@@ -2397,8 +2382,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());
}
@@ -2406,8 +2392,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());
}
@@ -2423,7 +2410,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:
@@ -2462,7 +2449,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 {
@@ -2474,6 +2461,10 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Loc = ASE->getBase()->getExprLoc();
Range = ASE->getBase()->getSourceRange();
MsgParam = 2;
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
+ D = const_cast<ValueDecl *>(DRE->getDecl());
+ }
} else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
BinaryOperator::Opcode Op = BO->getOpcode();
if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
@@ -2481,9 +2472,17 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
if (BO->getRHS()->getType()->isIntegerType()) {
Loc = BO->getLHS()->getExprLoc();
Range = BO->getLHS()->getSourceRange();
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParenImpCasts())) {
+ D = const_cast<ValueDecl *>(DRE->getDecl());
+ }
} else {
Loc = BO->getRHS()->getExprLoc();
Range = BO->getRHS()->getSourceRange();
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(BO->getRHS()->IgnoreParenImpCasts())) {
+ D = const_cast<ValueDecl *>(DRE->getDecl());
+ }
}
MsgParam = 1;
}
@@ -2494,6 +2493,10 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Loc = UO->getSubExpr()->getExprLoc();
Range = UO->getSubExpr()->getSourceRange();
MsgParam = 1;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(
+ UO->getSubExpr()->IgnoreParenImpCasts())) {
+ D = const_cast<ValueDecl *>(DRE->getDecl());
+ }
}
} else {
if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
@@ -2558,13 +2561,12 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
}
}
}
-
- unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_usage_in_main_args
+
+ unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_usage_main_argv
: diag::warn_unsafe_buffer_operation;
-
+
if (D) {
- S.Diag(Loc, DiagID)
- << MsgParam << D << Range;
+ S.Diag(Loc, DiagID) << MsgParam << D << Range;
} else {
S.Diag(Loc, DiagID) << MsgParam << Range;
}
@@ -2652,7 +2654,7 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
const FixitStrategy &VarTargetTypes) override {
assert(!SuggestSuggestions &&
"Unsafe buffer usage fixits displayed without suggestions!");
-
+
bool IsMainArg = false;
if (const auto *PVD = dyn_cast<ParmVarDecl>(Variable)) {
if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext())) {
@@ -2661,8 +2663,8 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
}
}
}
-
- unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_variable_in_main_args
+
+ unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_variable_main_argv
: diag::warn_unsafe_buffer_variable;
S.Diag(Variable->getLocation(), DiagID)
@@ -2704,7 +2706,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
}
@@ -2806,8 +2808,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;
@@ -3068,7 +3069,7 @@ static bool shouldSuggestUnsafeBufferUsageSuggestions(const Sema &S) {
}
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
- TranslationUnitDecl *TU) {
+ TranslationUnitDecl *TU) {
if (!TU)
return; // This is unexpected, give up quietly.
@@ -3202,13 +3203,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;
@@ -3289,12 +3290,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);
}
}
}
@@ -3331,7 +3330,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())) {
@@ -3362,8 +3360,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;
}
@@ -3392,7 +3390,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"
@@ -3401,10 +3399,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"
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
new file mode 100644
index 00000000000000..e8b8227eab47e8
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -Wunsafe-buffer-usage -fsafe-buffer-usage-suggestions -verify=expected,both %s
+// RUN: %clang_cc1 -Wunsafe-buffer-usage -Wno-unsafe-buffer-usage-main-argv -fsafe-buffer-usage-suggestions -verify=ignored,both %s
+
+int main(int argc, char **argv) {
+ // expected-warning at +1{{unsafe buffer access}}
+ char c = argv[1][0];
+
+ int *p = nullptr;
+ // both-warning at +1{{unsafe buffer access}}
+ return p[5];
+}
+
+int other_func(int argc, char **argv) {
+ // both-warning at +1{{unsafe buffer access}}
+ return argv[1][0];
+}
>From e07d55c87dc7ad906cc66848c3995dcd573cf75c Mon Sep 17 00:00:00 2001
From: Shreya Jain <jainshreya at google.com>
Date: Wed, 7 Oct 2026 21:39:30 +0000
Subject: [PATCH 3/4] Apply review feedback: Extract isMainParam helper
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 -
clang/lib/Sema/AnalysisBasedWarnings.cpp | 664 +++++++++---------
2 files changed, 332 insertions(+), 334 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 67ef836ec08180..69f97ba4eee523 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13918,7 +13918,6 @@ def warn_unsafe_buffer_variable_main_argv : Warning<
"%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
"does not perform bounds checks}1">,
InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
-
def warn_unsafe_buffer_variable : Warning<
"%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
"does not perform bounds checks}1">,
@@ -13928,7 +13927,6 @@ def warn_unsafe_buffer_usage_main_argv : Warning<
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
"field %1 prone to unsafe buffer manipulation}0">,
InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
-
def warn_unsafe_buffer_operation : Warning<
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 05fae91163bb24..e9a389e502be48 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -71,60 +71,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.
@@ -294,8 +295,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())
@@ -330,9 +330,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.
@@ -351,8 +352,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;
@@ -375,8 +375,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();
@@ -393,11 +393,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) {
@@ -570,8 +569,7 @@ 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.
@@ -630,7 +628,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;
@@ -804,12 +802,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())
@@ -821,7 +821,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.
@@ -898,7 +898,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.
@@ -921,7 +921,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 ");
@@ -943,16 +944,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(
@@ -1019,9 +1020,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) {
@@ -1037,8 +1038,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: {
@@ -1047,8 +1048,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: {
@@ -1123,13 +1124,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;
}
@@ -1299,32 +1300,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;
}
@@ -1340,63 +1341,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;
@@ -1511,12 +1513,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();
@@ -1530,7 +1533,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;
}
@@ -1587,7 +1590,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;
@@ -1618,7 +1626,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))
@@ -1720,7 +1733,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 ||
@@ -1970,10 +1983,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; }
@@ -2068,18 +2081,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;
@@ -2125,7 +2138,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());
}
@@ -2169,42 +2182,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) {
@@ -2216,42 +2230,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));
@@ -2263,9 +2278,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());
}
@@ -2285,20 +2300,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;
}
};
@@ -2319,6 +2336,7 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
DiagList Warnings;
public:
+
ConsumedWarningsHandler(Sema &S) : S(S) {}
void emitDiagnostics() override {
@@ -2332,8 +2350,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());
}
@@ -2343,9 +2361,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());
}
@@ -2353,18 +2371,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());
}
@@ -2372,9 +2388,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());
}
@@ -2382,9 +2397,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());
}
@@ -2392,9 +2406,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());
}
@@ -2408,9 +2421,17 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
//===----------------------------------------------------------------------===//
namespace {
+
+static bool isMainParam(const Decl *D) {
+ if (const auto *PVD = dyn_cast_or_null<ParmVarDecl>(D))
+ if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext()))
+ return FD->isMain();
+ return false;
+}
+
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:
@@ -2449,7 +2470,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 {
@@ -2462,9 +2483,8 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Range = ASE->getBase()->getSourceRange();
MsgParam = 2;
if (const auto *DRE =
- dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
+ dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts()))
D = const_cast<ValueDecl *>(DRE->getDecl());
- }
} else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
BinaryOperator::Opcode Op = BO->getOpcode();
if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
@@ -2473,16 +2493,14 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Loc = BO->getLHS()->getExprLoc();
Range = BO->getLHS()->getSourceRange();
if (const auto *DRE =
- dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParenImpCasts())) {
+ dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParenImpCasts()))
D = const_cast<ValueDecl *>(DRE->getDecl());
- }
} else {
Loc = BO->getRHS()->getExprLoc();
Range = BO->getRHS()->getSourceRange();
if (const auto *DRE =
- dyn_cast<DeclRefExpr>(BO->getRHS()->IgnoreParenImpCasts())) {
+ dyn_cast<DeclRefExpr>(BO->getRHS()->IgnoreParenImpCasts()))
D = const_cast<ValueDecl *>(DRE->getDecl());
- }
}
MsgParam = 1;
}
@@ -2493,10 +2511,9 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Loc = UO->getSubExpr()->getExprLoc();
Range = UO->getSubExpr()->getSourceRange();
MsgParam = 1;
- if (const auto *DRE = dyn_cast<DeclRefExpr>(
- UO->getSubExpr()->IgnoreParenImpCasts())) {
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParenImpCasts()))
D = const_cast<ValueDecl *>(DRE->getDecl());
- }
}
} else {
if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
@@ -2553,23 +2570,14 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
"Variables blamed for unsafe buffer usage without suggestions!");
S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
} else {
- bool IsMainArg = false;
- if (const auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
- if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext())) {
- if (FD->isMain()) {
- IsMainArg = true;
- }
- }
- }
+ unsigned DiagID = isMainParam(D)
+ ? diag::warn_unsafe_buffer_usage_main_argv
+ : diag::warn_unsafe_buffer_operation;
- unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_usage_main_argv
- : diag::warn_unsafe_buffer_operation;
-
- if (D) {
+ if (D)
S.Diag(Loc, DiagID) << MsgParam << D << Range;
- } else {
+ else
S.Diag(Loc, DiagID) << MsgParam << Range;
- }
if (SuggestSuggestions) {
S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
}
@@ -2655,17 +2663,9 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
assert(!SuggestSuggestions &&
"Unsafe buffer usage fixits displayed without suggestions!");
- bool IsMainArg = false;
- if (const auto *PVD = dyn_cast<ParmVarDecl>(Variable)) {
- if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext())) {
- if (FD->isMain()) {
- IsMainArg = true;
- }
- }
- }
-
- unsigned DiagID = IsMainArg ? diag::warn_unsafe_buffer_variable_main_argv
- : diag::warn_unsafe_buffer_variable;
+ unsigned DiagID = isMainParam(Variable)
+ ? diag::warn_unsafe_buffer_variable_main_argv
+ : diag::warn_unsafe_buffer_variable;
S.Diag(Variable->getLocation(), DiagID)
<< Variable << (Variable->getType()->isPointerType() ? 0 : 1)
@@ -2706,7 +2706,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
}
@@ -2808,7 +2808,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;
@@ -3069,7 +3070,7 @@ static bool shouldSuggestUnsafeBufferUsageSuggestions(const Sema &S) {
}
void clang::sema::AnalysisBasedWarnings::IssueWarnings(
- TranslationUnitDecl *TU) {
+ TranslationUnitDecl *TU) {
if (!TU)
return; // This is unexpected, give up quietly.
@@ -3203,13 +3204,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;
@@ -3290,10 +3291,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);
}
}
}
@@ -3330,6 +3333,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())) {
@@ -3360,8 +3364,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;
}
@@ -3390,7 +3394,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"
@@ -3399,14 +3403,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 8a0b12df47db33ab090575d7ae9dda3f3f9be4d0 Mon Sep 17 00:00:00 2001
From: Shreya Jain <jainshreya at google.com>
Date: Thu, 8 Oct 2026 19:06:25 +0000
Subject: [PATCH 4/4] Address review feedback: Use BufferOperand and
refersMainParam
---
clang/docs/ReleaseNotes.md | 4 ++
clang/docs/SafeBuffers.md | 5 ++
.../clang/Basic/DiagnosticSemaKinds.td | 25 +++++-----
clang/lib/Sema/AnalysisBasedWarnings.cpp | 47 ++++++++++---------
.../warn-unsafe-buffer-usage-main-argv.cpp | 2 +-
5 files changed, 45 insertions(+), 38 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 25299915441501..94e6facc20e650 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -573,6 +573,10 @@ features cannot lower the translation-unit ABI level;
- Improve Clang diagnoses when unary `__imag` operator with non-complex type operand is used as lvalue. (#GH222383)
+- Added `-Wunsafe-buffer-usage-main-argv` as a diagnostic group under
+ `-Wunsafe-buffer-usage` to control warnings on `main`'s `argv` parameter,
+ allowing users to suppress them with `-Wno-unsafe-buffer-usage-main-argv`.
+
### Improvements to Clang's time-trace
### Improvements to Coverage Mapping
diff --git a/clang/docs/SafeBuffers.md b/clang/docs/SafeBuffers.md
index 4cd98fcbda1333..8e41d1c6af591a 100644
--- a/clang/docs/SafeBuffers.md
+++ b/clang/docs/SafeBuffers.md
@@ -353,6 +353,11 @@ There are a few natural reasons to use this pragma:
never be converted to C++) or with the code that simply haven't been converted
yet.
+- In `main(int argc, char **argv)`, where the function signature is fixed by the
+ language standard and `argv` cannot be changed to a `std::span`. Warnings on
+ `main`'s `argv` parameter can also be selectively suppressed via the
+ `-Wno-unsafe-buffer-usage-main-argv` compiler flag.
+
Interoperation with unsafe code may require a lot of suppressions.
You are encouraged to introduce "unsafe wrapper functions" for various unsafe
operations that you need to perform regularly.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 69f97ba4eee523..4dfd16de672629 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13914,24 +13914,21 @@ def err_cast_from_randomized_struct : Error<
"casting from randomized structure pointer type %0 to %1">;
// Unsafe buffer usage diagnostics.
-def warn_unsafe_buffer_variable_main_argv : Warning<
+defvar UnsafeBufferVariableMsg =
"%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
- "does not perform bounds checks}1">,
- InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
-def warn_unsafe_buffer_variable : Warning<
- "%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that "
- "does not perform bounds checks}1">,
- InGroup<UnsafeBufferUsage>, DefaultIgnore;
-def warn_unsafe_buffer_usage_main_argv : Warning<
+ "does not perform bounds checks}1";
+defvar UnsafeBufferOperationMsg =
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
- "unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
- "field %1 prone to unsafe buffer manipulation}0">,
+ "unsafe buffer access|function introduces unsafe buffer manipulation|"
+ "unsafe invocation of %1|field %1 prone to unsafe buffer manipulation}0";
+def warn_unsafe_buffer_variable : Warning<UnsafeBufferVariableMsg>,
+ InGroup<UnsafeBufferUsage>, DefaultIgnore;
+def warn_unsafe_buffer_variable_main_argv : Warning<UnsafeBufferVariableMsg>,
InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
-def warn_unsafe_buffer_operation : Warning<
- "%select{unsafe pointer operation|unsafe pointer arithmetic|"
- "unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
- "field %1 prone to unsafe buffer manipulation}0">,
+def warn_unsafe_buffer_operation : Warning<UnsafeBufferOperationMsg>,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
+def warn_unsafe_buffer_operation_main_argv : Warning<UnsafeBufferOperationMsg>,
+ InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
def warn_unsafe_buffer_libc_call : Warning<
"function %0 is unsafe">,
InGroup<UnsafeBufferUsageInLibcCall>, DefaultIgnore;
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index e9a389e502be48..12252071042a21 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2422,13 +2422,21 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
namespace {
-static bool isMainParam(const Decl *D) {
+bool isMainParam(const Decl *D) {
if (const auto *PVD = dyn_cast_or_null<ParmVarDecl>(D))
if (const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext()))
return FD->isMain();
return false;
}
+bool refersMainParam(const Expr *E) {
+ if (!E)
+ return false;
+ if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(E->IgnoreParenImpCasts()))
+ return isMainParam(DRE->getDecl());
+ return false;
+}
+
class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Sema &S;
bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions?
@@ -2478,29 +2486,24 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
SourceRange Range;
unsigned MsgParam = 0;
NamedDecl *D = nullptr;
+ const Expr *BufferOperand = nullptr;
if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
- Loc = ASE->getBase()->getExprLoc();
- Range = ASE->getBase()->getSourceRange();
+ BufferOperand = ASE->getBase();
+ Loc = BufferOperand->getExprLoc();
+ Range = BufferOperand->getSourceRange();
MsgParam = 2;
- if (const auto *DRE =
- dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts()))
- D = const_cast<ValueDecl *>(DRE->getDecl());
} else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
BinaryOperator::Opcode Op = BO->getOpcode();
if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
Op == BO_SubAssign) {
if (BO->getRHS()->getType()->isIntegerType()) {
- Loc = BO->getLHS()->getExprLoc();
- Range = BO->getLHS()->getSourceRange();
- if (const auto *DRE =
- dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParenImpCasts()))
- D = const_cast<ValueDecl *>(DRE->getDecl());
+ BufferOperand = BO->getLHS();
+ Loc = BufferOperand->getExprLoc();
+ Range = BufferOperand->getSourceRange();
} else {
- Loc = BO->getRHS()->getExprLoc();
- Range = BO->getRHS()->getSourceRange();
- if (const auto *DRE =
- dyn_cast<DeclRefExpr>(BO->getRHS()->IgnoreParenImpCasts()))
- D = const_cast<ValueDecl *>(DRE->getDecl());
+ BufferOperand = BO->getRHS();
+ Loc = BufferOperand->getExprLoc();
+ Range = BufferOperand->getSourceRange();
}
MsgParam = 1;
}
@@ -2508,12 +2511,10 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
UnaryOperator::Opcode Op = UO->getOpcode();
if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
Op == UO_PostDec) {
- Loc = UO->getSubExpr()->getExprLoc();
- Range = UO->getSubExpr()->getSourceRange();
+ BufferOperand = UO->getSubExpr();
+ Loc = BufferOperand->getExprLoc();
+ Range = BufferOperand->getSourceRange();
MsgParam = 1;
- if (const auto *DRE =
- dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParenImpCasts()))
- D = const_cast<ValueDecl *>(DRE->getDecl());
}
} else {
if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
@@ -2570,8 +2571,8 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
"Variables blamed for unsafe buffer usage without suggestions!");
S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
} else {
- unsigned DiagID = isMainParam(D)
- ? diag::warn_unsafe_buffer_usage_main_argv
+ unsigned DiagID = refersMainParam(BufferOperand)
+ ? diag::warn_unsafe_buffer_operation_main_argv
: diag::warn_unsafe_buffer_operation;
if (D)
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
index e8b8227eab47e8..758ff7af23d662 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
@@ -3,7 +3,7 @@
int main(int argc, char **argv) {
// expected-warning at +1{{unsafe buffer access}}
- char c = argv[1][0];
+ char c = argv[1][0];
int *p = nullptr;
// both-warning at +1{{unsafe buffer access}}
More information about the cfe-commits
mailing list