[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 19:52:51 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/5] [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/5] [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/5] 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/5] 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}}

>From 0191ffd01ab176e61ac753a5b2868f479b48e57d Mon Sep 17 00:00:00 2001
From: Shreya Jain <jainshreya at google.com>
Date: Thu, 8 Oct 2026 21:49:51 +0000
Subject: [PATCH 5/5] Address review comments on main argv tests

---
 .../test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp  | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

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 758ff7af23d662..fc4297b33033fe 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-main-argv.cpp
@@ -1,10 +1,17 @@
 // 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
+// RUN: %clang_cc1 -Wunsafe-buffer-usage -Wno-unsafe-buffer-usage-main-argv -fsafe-buffer-usage-suggestions -verify=both %s
 
 int main(int argc, char **argv) {
   // expected-warning at +1{{unsafe buffer access}}
   char c = argv[1][0];
 
+  // expected-warning at +1{{unsafe pointer arithmetic}}
+  char **ptr1 = argv + 1;
+  // expected-warning at +1{{unsafe pointer arithmetic}}
+  argv++;
+  // expected-warning at +1{{unsafe pointer arithmetic}}
+  argv += 1;
+
   int *p = nullptr;
   // both-warning at +1{{unsafe buffer access}}
   return p[5];



More information about the cfe-commits mailing list